/** * 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')); } } }
/** * Display a notice asking the user to take the Broken Link Checker user survey. * * @return void */ function blc_display_survey_notice() { //Only people who can actually use the plugin will see the notice if (!current_user_can('manage_links')) { return; } if (!empty($_GET['dismiss-blc-survey'])) { //The user has chosen to hide the survey notice $blc_config = blc_get_configuration(); $blc_config->options['hide_surveyio_notice'] = true; $blc_config->save_options(); return; } $survey_url = 'http://survey.io/survey/7fbf0'; $msg = sprintf('<strong>Help improve Broken Link Checker - <a href="%s" target="_blank" title="This link will open in a new window" id="blc-take-survey-link">take a user feedback survey!</a></strong> <br><a href="%s">Hide this notice</a>', $survey_url, esc_attr(add_query_arg('dismiss-blc-survey', 1))); echo '<div id="update-nag" class="blc-survey-notice" style="text-align: left; padding-left: 10px;">' . $msg . '</div>'; //Auto-hide the notice after the user clicks the survey link ?> <script type="text/javascript"> jQuery(function($){ $('#blc-take-survey-link').click(function(){ $('.blc-survey-notice').hide('fast'); $.get('<?php echo esc_js(add_query_arg('dismiss-blc-survey', 1, admin_url())); ?> '); }); }); </script> <?php }
/** * Create and/or upgrade the plugin's database tables. * * @return bool */ public static function upgrade_database() { global $wpdb, $blclog; $conf = blc_get_configuration(); $current = $conf->options['current_db_version']; if ($current != 0 && $current < 4) { //The 4th DB version makes a lot of backwards-incompatible changes to the main //BLC tables, so instead of upgrading we just throw them away and recreate. if (!blcDatabaseUpgrader::drop_tables()) { return false; } $current = 0; } //Create/update the plugin's tables if (!blcDatabaseUpgrader::make_schema_current()) { return false; } if ($current != 0) { if ($current < 5) { blcDatabaseUpgrader::upgrade_095(); } } $conf->options['current_db_version'] = BLC_DATABASE_VERSION; $conf->save_options(); $blclog->info('Database successfully upgraded.'); return true; }
/** * Notify the link checker that there are unsynched items * that might contain links (e.g. a new or edited post). * * @return void */ function blc_got_unsynched_items() { $conf = blc_get_configuration(); if (!$conf->options['need_resynch']) { $conf->options['need_resynch'] = true; $conf->save_options(); } }
/** * Class "constructor". * * @param array $default_active_modules An array of module ids specifying which modules are active by default. * @return void */ function init($default_active_modules = null) { $this->module_dir = realpath(dirname(__FILE__) . '/../modules'); $this->plugin_conf = blc_get_configuration(); $this->default_active_modules = $default_active_modules; $this->loaded = array(); $this->instances = array(); add_filter('extra_plugin_headers', array(&$this, 'inject_module_headers')); }
function save_settings() { $information = array(); $information['result'] = 'NOTCHANGE'; $new_check_threshold = intval($_POST['check_threshold']); if ($new_check_threshold > 0) { $conf = blc_get_configuration(); $conf->options['check_threshold'] = $new_check_threshold; if ($conf->save_options()) { $information['result'] = 'SUCCESS'; } } return $information; }
/** * Check a FileServe link. * * See the FileServe API documentation for details: * http://app.fileserve.com/api/download/ * * @param string $url File URL. * @return array */ function check($url) { $result = array('final_url' => $url, 'redirect_count' => 0, 'timeout' => false, 'broken' => false, 'log' => sprintf("<em>(%s)</em>\n\n", __('Using FileServe API', 'broken-link-checker')), 'result_hash' => '', 'status_code' => '', 'status_text' => ''); //We know the URL will match because ModuleCheckerUrlPattern matched. preg_match('@^http://(?:www\\.)?fileserve\\.com/file/([\\w\\d]+?)(?:/|$|[?#])@i', $url, $matches); $file_id = $matches[1]; $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout'], 'body' => array('shorten' => $file_id)); $start = microtime_float(); $response = wp_remote_post($this->fileserve_api_url, $args); $result['request_duration'] = microtime_float() - $start; $error_code = 0; if (is_wp_error($response)) { $result['log'] .= "Error : " . $response->get_error_message(); $result['broken'] = true; $result['http_code'] = 0; } else { $result['http_code'] = intval($response['response']['code']); if ($result['http_code'] == 200) { //In this case, the HTTP code returned by is not meaningful in itself, //so we won't store it or display it to the user. $result['http_code'] = 0; $json = json_decode($response['body'], false); if (isset($json->error_code)) { $error_code = intval($json->error_code); } $failure_codes = array(310 => 'Invalid request', 403 => 'Not premium', 404 => 'Invalid link', 601 => 'Limited free download', 602 => 'Number of concurrent download exceeded', 603 => 'Too many invalid capcha', 605 => 'Expired premium', 606 => 'Invalid file ID', 607 => 'File not available', 608 => 'File not available'); if (array_key_exists($error_code, $failure_codes)) { $result['broken'] = true; $result['status_code'] = BLC_LINK_STATUS_ERROR; $result['status_text'] = __('Not Found', 'broken-link-checker'); $result['log'] .= sprintf(__('FileServe : %d %s', 'broken-link-checker') . "\n", $error_code, $failure_codes[$error_code]); } else { $result['status_code'] = BLC_LINK_STATUS_OK; $result['status_text'] = _x('OK', 'link status', 'broken-link-checker'); } //$result['log'] .= "API response :\n" . htmlspecialchars(print_r((array)$json, true)); $result['log'] .= "API response :\n<code>" . htmlspecialchars($response['body']) . "</code>\n"; } else { //Unexpected error. $result['log'] .= $response['body']; $result['broken'] = true; } } //Generate the result hash (used for detecting false positives) $result['result_hash'] = implode('|', array('fileserve', $result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', $error_code)); return $result; }
function __construct() { //Init. the available native filters. $this->native_filters = array('all' => array('params' => array('where_expr' => '1'), 'name' => __('All', 'broken-link-checker'), 'heading' => __('Detected Links', 'broken-link-checker'), 'heading_zero' => __('No links found (yet)', 'broken-link-checker'), 'native' => true), 'broken' => array('params' => array('where_expr' => '( broken = 1 )', 's_include_dismissed' => false), 'name' => __('Broken', 'broken-link-checker'), 'heading' => __('Broken Links', 'broken-link-checker'), 'heading_zero' => __('No broken links found', 'broken-link-checker'), 'native' => true), 'warnings' => array('params' => array('where_expr' => '( warning = 1 )', 's_include_dismissed' => false), 'name' => _x('Warnings', 'filter name', 'broken-link-checker'), 'heading' => __('Warnings', 'filter heading', 'broken-link-checker'), 'heading_zero' => __('No warnings found', 'broken-link-checker'), 'native' => true), 'redirects' => array('params' => array('where_expr' => '( redirect_count > 0 )', 's_include_dismissed' => false), 'name' => __('Redirects', 'broken-link-checker'), 'heading' => __('Redirected Links', 'broken-link-checker'), 'heading_zero' => __('No redirects found', 'broken-link-checker'), 'native' => true), 'dismissed' => array('params' => array('where_expr' => '( dismissed = 1 )'), 'name' => __('Dismissed', 'broken-link-checker'), 'heading' => __('Dismissed Links', 'broken-link-checker'), 'heading_zero' => __('No dismissed links found', 'broken-link-checker'), 'native' => true)); //The user can turn off warnings. In that case, all errors will show up in the "broken" filter instead. $conf = blc_get_configuration(); if (!$conf->get('warnings_enabled')) { unset($this->native_filters['warnings']); } //Create the special "search" filter $this->search_filter = array('name' => __('Search', 'broken-link-checker'), 'heading' => __('Search Results', 'broken-link-checker'), 'heading_zero' => __('No links found for your query', 'broken-link-checker'), 'params' => array(), 'use_url_params' => true, 'hidden' => true); //These search arguments may be passed via the URL if the filter's 'use_url_params' field is set to True. //They map to the fields of the search form on the Tools -> Broken Links page. Only these arguments //can be used in user-defined filters. $this->valid_url_params = array('s_link_text', 's_link_url', 's_parser_type', 's_container_type', 's_link_type', 's_http_code', 's_filter'); }
function save_settings() { $information = array(); $information['result'] = 'NOTCHANGE'; $new_check_threshold = intval($_POST['check_threshold']); if (update_option('mainwp_child_blc_max_number_of_links', intval($_POST['max_number_of_links']))) { $information['result'] = 'SUCCESS'; } if ($new_check_threshold > 0) { $conf = blc_get_configuration(); $conf->options['check_threshold'] = $new_check_threshold; if ($conf->save_options()) { $information['result'] = 'SUCCESS'; } } return $information; }
/** * blcHTMLLink::unlink_callback() * * @access private * * @param array $link * @param array $params * @return string */ function unlink_callback($link, $params) { //Skip links that don't match the specified URL if ($link['href'] != $params['old_url']) { return $link['#raw']; } $config = blc_get_configuration(); if ($config->options['mark_removed_links']) { //Leave only the anchor text + the removed_link CSS class return sprintf('<span class="removed_link" title="%s">%s</span>', esc_attr($link['href']), $link['#link_text']); } else { //Just the anchor text return $link['#link_text']; } }
/** * Decide whether the result of the latest check means that the link is really broken * or should just be reported as a warning. * * @param array $check_results * @return array */ private function decide_warning_state($check_results) { if (!$check_results['broken'] && !$check_results['warning']) { //Nothing to do, this is a working link. return $check_results; } $configuration = blc_get_configuration(); if (!$configuration->get('warnings_enabled', true)) { //The user wants all failures to be reported as "broken", regardless of severity. if ($check_results['warning']) { $check_results['broken'] = true; $check_results['warning'] = false; } return $check_results; } $warning_reason = null; $failure_count = $this->check_count; $failure_duration = $this->first_failure != 0 ? time() - $this->first_failure : 0; //These could be configurable, but lets put that off until someone actually asks for it. $duration_threshold = 24 * 3600; $count_threshold = 3; //We can't just use ($check_results['status_code'] == 'warning' because some "warning" problems are not //temporary. For example, region-restricted YouTube videos use the "warning" status code. $maybe_temporary_error = false; //Some basic heuristics to determine if this failure might be temporary. //---------------------------------------------------------------------- if ($check_results['timeout']) { $maybe_temporary_error = true; $warning_reason = 'Timeouts are sometimes caused by high server load or other temporary issues.'; } $error_code = isset($check_results['error_code']) ? $check_results['error_code'] : ''; if ($error_code === 'connection_failed') { $maybe_temporary_error = true; $warning_reason = 'Connection failures are sometimes caused by high server load or other temporary issues.'; } $http_code = intval($check_results['http_code']); $temporary_http_errors = array(408, 420, 429, 502, 503, 504, 509, 520, 522, 524); if (in_array($http_code, $temporary_http_errors)) { $maybe_temporary_error = true; if (in_array($http_code, array(502, 503, 504, 509))) { $warning_reason = sprintf('HTTP error %d usually means that the site is down due to high server load or a configuration problem. ' . 'This error is often temporary and will go away after while.', $http_code); } else { $warning_reason = 'This HTTP error is often temporary.'; } } //---------------------------------------------------------------------- //Attempt to detect false positives. $suspected_false_positive = false; //A "403 Forbidden" error on an internal link usually means something on the site is blocking automated //requests. Possible culprits include hotlink protection rules in .htaccess, badly configured IDS, and so on. $is_internal_link = $this->is_internal_to_domain(); if ($is_internal_link && $http_code == 403) { $suspected_false_positive = true; $warning_reason = 'This might be a false positive. Make sure the link is not password-protected, ' . 'and that your server is not set up to block automated requests.'; } //Some hosting providers turn off loopback connections. This causes all internal links to be reported as broken. if ($is_internal_link && in_array($error_code, array('connection_failed', 'couldnt_resolve_host'))) { $suspected_false_positive = true; $warning_reason = 'This is probably a false positive. '; if ($error_code === 'connection_failed') { $warning_reason .= 'The plugin could not connect to your site. That usually means that your ' . 'hosting provider has disabled loopback connections.'; } elseif ($error_code === 'couldnt_resolve_host') { $warning_reason .= 'The plugin could not connect to your site because DNS resolution failed. ' . 'This could mean DNS is configured incorrectly on your server.'; } } //---------------------------------------------------------------------- //Temporary problems and suspected false positives start out as warnings. False positives stay that way //indefinitely because they are usually caused by bugs and server configuration issues, not temporary downtime. if ($maybe_temporary_error && $failure_count < $count_threshold || $suspected_false_positive) { $check_results['warning'] = true; $check_results['broken'] = false; } //Upgrade temporary warnings to "broken" after X consecutive failures or Y hours, whichever comes first. $threshold_reached = $failure_count >= $count_threshold || $failure_duration >= $duration_threshold; if ($check_results['warning']) { if ($maybe_temporary_error && $threshold_reached && !$suspected_false_positive) { $check_results['warning'] = false; $check_results['broken'] = true; } } if (!empty($warning_reason) && $check_results['warning']) { $formatted_reason = "\n==========\n" . 'Severity: Warning' . "\n" . 'Reason: ' . trim($warning_reason) . "\n==========\n"; $check_results['log'] .= $formatted_reason; } return $check_results; }
/** * Perform a HEAD request to the specified URL. * * Note : * * Since the MediaFire checker works by parsing the "Location" header, redirect following * _must_ be disabled. This can become a problem on servers where WP is forced to fall back * on using WP_Http_Fopen which ignores the 'redirection' flag. WP_Http_Fsockopen would work, * but it has the lowest priority of all transports. * * Alas, there is no way to reliably influence which transport is chosen - the WP_Http::_getTransport * function caches the available choices, so plugins can disable individual transports only during * its first run. Therefore, we must pick the best transport manually. * * @param string $url * @return array|WP_Error */ function head($url) { //Only consider transports that allow redirection to be disabled. $args = array(); if (class_exists('WP_Http_ExtHttp') && true === WP_Http_ExtHttp::test($args)) { $transport = new WP_Http_ExtHttp(); } else { if (class_exists('WP_Http_Curl') && true === WP_Http_Curl::test($args)) { $transport = new WP_Http_Curl(); } else { if (class_exists('WP_Http_Curl') && true === WP_Http_Fsockopen::test($args)) { $transport = new WP_Http_Fsockopen(); } else { return new WP_Error('no_suitable_transport', "No suitable HTTP transport found. Please upgrade to a more recent version of PHP or install the CURL extension."); } } } $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout'], 'redirection' => 0, 'method' => 'HEAD'); return $transport->request($url, $args); }
/** * A hook for the 'wp_head' action. Outputs the user-defined broken link CSS. * * @return void */ function hook_wp_head() { $conf = blc_get_configuration(); echo '<style type="text/css">', $conf->options['broken_link_css'], '</style>'; }
/** * Show an admin notice that explains what the "Warnings" section under "Tools -> Broken Links" does. * The user can hide the notice. */ public function show_warnings_section_notice() { $is_warnings_section = isset($_GET['filter_id']) && $_GET['filter_id'] === 'warnings' && isset($_GET['page']) && $_GET['page'] === 'view-broken-links'; if (!($is_warnings_section && current_user_can('edit_others_posts'))) { return; } //Let the user hide the notice. $conf = blc_get_configuration(); $notice_name = 'show_warnings_section_hint'; if (isset($_GET[$notice_name]) && is_numeric($_GET[$notice_name])) { $conf->set($notice_name, (bool) $_GET[$notice_name]); $conf->save_options(); } if (!$conf->get($notice_name, true)) { return; } printf('<div class="updated"> <p>%1$s</p> <p> <a href="%2$s">%3$s</a> | <a href="%4$s">%5$s</a> <p> </div>', __('The "Warnings" page lists problems that are probably temporary or suspected to be false positives.<br> Warnings that persist for a long time will usually be reclassified as broken links.', 'broken-link-checker'), esc_attr(add_query_arg($notice_name, '0')), _x('Hide notice', 'admin notice under Tools - Broken links - Warnings', 'broken-link-checker'), esc_attr(admin_url('options-general.php?page=link-checker-settings#blc_warning_settings')), _x('Change warning settings', 'a link from the admin notice under Tools - Broken links - Warnings', 'broken-link-checker')); }
/** * Check the status of one or more MegaUpload files. * * The MegaUpload API that is used in this function isn't documented anywhere. * The input and output data formats were reverse-engineered by sniffing the * HTTP requests made by the "Mega Manager" tool. * * @param array|string $file_ids * @return array|WP_Error */ function check_files($file_ids) { if (is_string($file_ids)) { $file_ids = array($file_ids); } //The API expects input in this format : id0=file1id&id1=file2id&... $request_ids = array(); $counter = 0; foreach ($file_ids as $file_id) { $id = 'id' . $counter; $request_ids[$id] = $file_id; $counter++; } $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout'], 'body' => $request_ids); //Submit the request $rez = wp_remote_post('http://www.megaupload.com/mgr_linkcheck.php', $args); if (is_wp_error($rez)) { return $rez; } if ($rez['response']['code'] == 200 && !empty($rez['body'])) { $api_results = $this->parse_api_response($rez['body']); $results = array(); //Resort the results by real file IDs foreach ($api_results as $id => $file_info) { if (!array_key_exists($id, $request_ids)) { continue; } $results[$request_ids[$id]] = $file_info; } return $results; } else { return new WP_Error('megaupload_api_error', "MegaUpload API Error", $rez); } }
/** * Check a RapidShare file. * * @param string $url File URL. * @return array */ function check($url) { $result = array('final_url' => $url, 'redirect_count' => 0, 'timeout' => false, 'broken' => false, 'log' => sprintf("<em>(%s)</em>\n\n", __('Using RapidShare API', 'broken-link-checker')), 'result_hash' => '', 'status_code' => '', 'status_text' => ''); //We know the URL will match because ModuleCheckerUrlPattern matched. preg_match('@^https?://(?:[\\w\\d]+\\.)*rapidshare\\.\\w+/files/(\\d+)/([^&?#/]+?)(?:$|[&?#/])@i', $url, $matches); $file_id = $matches[1]; $file_name = $matches[2]; /* We use the checkfiles function to check file status. The RapidShare API docs can be found here : http://images.rapidshare.com/apidoc.txt The relevant function is documented thusly : sub=checkfiles Description: Gets status details about a list of given files. (files parameter limited to 3000 bytes. filenames parameter limited to 30000 bytes.) Parameters: files=comma separated list of file ids filenames=comma separated list of the respective filename. Example: files=50444381,50444382 filenames=test1.rar,test2.rar Reply fields: 1:File ID 2:Filename 3:Size (in bytes. If size is 0, this file does not exist.) 4:Server ID 5:Status integer, which can have the following numeric values: 0=File not found 1=File OK 3=Server down 4=File marked as illegal 6:Short host (Use the short host to get the best download mirror: http://rs$serverid$shorthost.rapidshare.com/files/$fileid/$filename) 7:MD5 (hexadecimal) Reply format: integer,string,integer,integer,integer,string,string */ $api_url = sprintf('http://api.rapidshare.com/cgi-bin/rsapi.cgi?sub=checkfiles&files=%d&filenames=%s', $file_id, $file_name); $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout']); $start = microtime_float(); $response = wp_remote_get($api_url, $args); $result['request_duration'] = microtime_float() - $start; $file_status = 0; $file_status_text = ''; //Is the response valid? if (is_wp_error($response)) { $result['log'] .= "Error : " . $response->get_error_message(); $result['broken'] = true; $result['http_code'] = 0; } else { $result['http_code'] = intval($response['response']['code']); if ($result['http_code'] == 200) { //Parse the API response $data = explode(',', $response['body']); //Check file status if (isset($data[4])) { $file_status = intval($data[4]); $file_status_text = ''; if ($file_status >= 0 && $file_status <= 6) { //Lets not confuse the user by showing the HTTP code we got from the API. //It's always "200" - whether the file exists or not. $result['http_code'] = 0; } switch ($file_status) { case 0: $file_status_text = 'File not found'; $result['broken'] = true; $result['status_code'] = BLC_LINK_STATUS_ERROR; $result['status_text'] = __('Not Found', 'broken-link-checker'); break; case 1: $file_status_text = 'File OK (Anonymous downloading)'; $result['status_code'] = BLC_LINK_STATUS_OK; $result['status_text'] = _x('OK', 'link status', 'broken-link-checker'); break; case 2: $file_status_text = 'File OK (TrafficShare direct download without any logging)'; $result['status_code'] = BLC_LINK_STATUS_OK; $result['status_text'] = _x('OK', 'link status', 'broken-link-checker'); break; case 3: $file_status_text = 'Server down'; $result['broken'] = true; $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __('RS Server Down', 'broken-link-checker'); break; case 4: $file_status_text = 'File marked as illegal'; $result['broken'] = true; $result['status_code'] = BLC_LINK_STATUS_ERROR; $result['status_text'] = __('File Blocked', 'broken-link-checker'); break; case 5: $file_status_text = 'Anonymous file locked because it has more than 10 downloads'; $result['broken'] = true; $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['status_text'] = __('File Locked', 'broken-link-checker'); break; case 6: $file_status_text = 'File OK (TrafficShare direct download with enabled logging)'; $result['status_code'] = BLC_LINK_STATUS_OK; $result['status_text'] = _x('OK', 'link status', 'broken-link-checker'); break; } $result['log'] .= sprintf(__('RapidShare : %s', 'broken-link-checker'), $file_status_text); } else { $result['log'] .= sprintf(__('RapidShare API error: %s', 'broken-link-checker'), $response['body']); } } else { //Unexpected error. $result['log'] .= $response['body']; $result['broken'] = true; } } //Generate the result hash (used for detecting false positives) $result['result_hash'] = implode('|', array('rapidshare', $result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', $file_status)); return $result; }
/** * Mark custom fields as unsynched when they're modified or deleted. * * @param array|int $meta_id * @param int $object_id * @param string $meta_key * @param string $meta_value * @return void */ function meta_modified($meta_id, $object_id = 0, $meta_key = '', $meta_value = '') { global $wpdb; //If object_id isn't specified then the hook was probably called from the //stupidly inconsistent delete_meta() function in /wp-admin/includes/post.php. if (empty($object_id)) { //We must manually retrieve object_id and meta_key from the DB. if (is_array($meta_id)) { $meta_id = array_shift($meta_id); } $meta = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE meta_id = %d", $meta_id), ARRAY_A); if (empty($meta)) { return; } $object_id = $meta['post_id']; $meta_key = $meta['meta_key']; } //Metadata changes only matter to us if the modified key //is one that the user wants checked. $conf =& blc_get_configuration(); if (!is_array($conf->options['custom_fields'])) { return; } if (!in_array($meta_key, $conf->options['custom_fields'])) { return; } $container =& blcContainerHelper::get_container(array($this->container_type, intval($object_id))); $container->mark_as_unsynched(); }
/** * Display installation errors (if any) on the Dashboard. * * @return void */ function blc_print_installation_errors() { $conf = blc_get_configuration(); if (!$conf->options['installation_failed']) { return; } $logger = new blcOptionLogger('blc_installation_log'); $log = $logger->get_messages(); $message = array('<strong>' . __('Broken Link Checker installation failed', 'broken-link-checker') . '</strong>', '', '<em>Installation log follows :</em>'); foreach ($log as $entry) { array_push($message, $entry); } $message = implode("<br>\n", $message); echo "<div class='error'><p>{$message}</p></div>"; }
/** * @param blcLink $link */ function column_new_url($link) { ?> <a href="<?php print esc_url($link->url); ?> " target='_blank' class='blc-link-url' title="<?php echo esc_attr($link->url); ?> " data-editable-url="<?php echo esc_attr($link->url); ?> "> <?php print esc_html($link->url); ?> </a> <?php //Output inline action links for the link/URL $actions = array(); $actions['edit'] = "<a href='javascript:void(0)' class='blc-edit-button' title='" . esc_attr(__('Edit this link', 'broken-link-checker')) . "'>" . __('Edit URL', 'broken-link-checker') . "</a>"; $actions['delete'] = "<a class='submitdelete blc-unlink-button' title='" . esc_attr(__('Remove this link from all posts', 'broken-link-checker')) . "' " . "href='javascript:void(0);'>" . __('Unlink', 'broken-link-checker') . "</a>"; if ($link->broken || $link->warning) { $actions['blc-discard-action'] = sprintf('<a href="#" title="%s" class="blc-discard-button">%s</a>', esc_attr(__('Remove this link from the list of broken links and mark it as valid', 'broken-link-checker')), __('Not broken', 'broken-link-checker')); } if (!$link->dismissed && ($link->broken || $link->warning || $link->redirect_count > 0)) { $actions['blc-dismiss-action'] = sprintf('<a href="#" title="%s" class="blc-dismiss-button">%s</a>', esc_attr(__('Hide this link and do not report it again unless its status changes', 'broken-link-checker')), __('Dismiss', 'broken-link-checker')); } else { if ($link->dismissed) { $actions['blc-undismiss-action'] = sprintf('<a href="#" title="%s" class="blc-undismiss-button">%s</a>', esc_attr(__('Undismiss this link', 'broken-link-checker')), __('Undismiss', 'broken-link-checker')); } } $actions['blc-recheck-action'] = sprintf('<a href="#" class="blc-recheck-button">%s</a>', __('Recheck', 'broken-link-checker')); if ($link->redirect_count > 0 && !empty($link->final_url) && $link->url != $link->final_url) { //TODO: Check if at least one instance has an editable URL. Otherwise this won't work. $actions['blc-deredirect-action'] = sprintf('<a href="#" class="blc-deredirect-button" title="%s">%s</a>', __('Replace this redirect with a direct link', 'broken-link-checker'), _x('Fix redirect', 'link action; replace one redirect with a direct link', 'broken-link-checker')); } //Only show the enabled actions. $conf = blc_get_configuration(); foreach ($conf->get('show_link_actions', $actions) as $name => $enabled) { if (!$enabled) { unset($actions[$name]); } } //Wrap actions with <span></span> and separate them with | characters. //Basically, this emulates the HTML structure that WP uses for post actions under Posts -> All Posts. $spans = array(); $is_first_action = true; foreach ($actions as $name => $html) { $spans[] = sprintf('<span class="%s">%s%s</span>', esc_attr($name), $is_first_action ? '' : ' | ', $html); $is_first_action = false; } echo '<div class="row-actions">'; echo implode('', $spans); echo '</div>'; ?> <div class="blc-url-editor-buttons"> <input type="button" class="button-secondary cancel alignleft blc-cancel-button" value="<?php echo esc_attr(__('Cancel', 'broken-link-checker')); ?> " /> <input type="button" class="button-primary save alignright blc-update-url-button" value="<?php echo esc_attr(__('Update URL', 'broken-link-checker')); ?> " /> <img class="waiting" style="display:none;" src="<?php echo esc_url(admin_url('images/wpspin_light.gif')); ?> " alt="" /> </div> <?php }
function check($url) { //Throttle API requests to avoid getting blocked due to quota violation. $delta = microtime_float() - $this->last_api_request; if ($delta < $this->api_grace_period) { usleep(($this->api_grace_period - $delta) * 1000000); } $result = array('final_url' => $url, 'redirect_count' => 0, 'timeout' => false, 'broken' => false, 'log' => "<em>(Using YouTube API)</em>\n\n", 'result_hash' => ''); $components = @parse_url($url); if (isset($components['query'])) { parse_str($components['query'], $query); } else { $query = array(); } //Extract the video or playlist ID from the URL $video_id = $playlist_id = null; if (strtolower($components['host']) === 'youtu.be') { $video_id = trim($components['path'], '/'); } else { if (strpos($components['path'], 'watch') !== false && isset($query['v'])) { $video_id = $query['v']; } else { if ($components['path'] == '/playlist') { $playlist_id = $query['list']; } else { if ($components['path'] == '/view_play_list') { $playlist_id = $query['p']; } } } } if (empty($playlist_id) && empty($video_id)) { $result['status_text'] = 'Unsupported URL Syntax'; $result['status_code'] = BLC_LINK_STATUS_UNKNOWN; return $result; } //Fetch video or playlist from the YouTube API if (!empty($video_id)) { $api_url = $this->get_video_resource_url($video_id); } else { $api_url = $this->get_playlist_resource_url($playlist_id); } $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout']); $start = microtime_float(); $response = wp_remote_get($api_url, $args); $result['request_duration'] = microtime_float() - $start; $this->last_api_request = $start; //Got anything? if (is_wp_error($response)) { $result['log'] .= "Error.\n" . $response->get_error_message(); //WP doesn't make it easy to distinguish between different internal errors. $result['broken'] = true; $result['http_code'] = 0; } else { $result['http_code'] = intval($response['response']['code']); if (!empty($video_id)) { $result = $this->check_video($response, $result); } else { $result = $this->check_playlist($response, $result); } } //The hash should contain info about all pieces of data that pertain to determining if the //link is working. $result['result_hash'] = implode('|', array('youtube', $result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', isset($result['state_name']) ? $result['state_name'] : '-', isset($result['state_reason']) ? $result['state_reason'] : '-')); return $result; }
function check($url) { $result = array('final_url' => $url, 'redirect_count' => 0, 'timeout' => false, 'broken' => false, 'log' => "<em>(Using YouTube API)</em>\n\n", 'result_hash' => ''); //Extract the video ID from the URL $components = @parse_url($url); parse_str($components['query'], $query); $video_id = $query['v']; //Fetch video data from the YouTube API $api_url = 'http://gdata.youtube.com/feeds/api/videos/' . $video_id; $conf =& blc_get_configuration(); $args = array('timeout' => $conf->options['timeout']); $start = microtime_float(); $response = wp_remote_get($api_url, $args); $result['request_duration'] = microtime_float() - $start; //Placeholders for video restriction data $state_name = $state_reason = ''; //Got anything? if (is_wp_error($response)) { $result['log'] .= "Error.\n" . $response->get_error_message(); //WP doesn't make it easy to distinguish between different internal errors. $result['broken'] = true; $result['http_code'] = 0; } else { $result['http_code'] = intval($response['response']['code']); switch ($result['http_code']) { case 404: //Not found $result['log'] .= __('Video Not Found', 'broken-link-checker'); $result['broken'] = true; $result['http_code'] = 0; $result['status_text'] = __('Video Not Found', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_ERROR; break; case 403: //Forbidden. Usually means that the video has been removed. Body contains details. $result['log'] .= $response['body']; $result['broken'] = true; $result['http_code'] = 0; $result['status_text'] = __('Video Removed', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_ERROR; break; case 400: //Bad request. Usually means that the video ID is incorrect. Body contains details. $result['log'] .= $response['body']; $result['broken'] = true; $result['http_code'] = 0; $result['status_text'] = __('Invalid Video ID', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_WARNING; break; case 200: //Video exists, but may be restricted. Check for <yt:state> tags. //See http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_yt:state //Can we count on an XML parser being installed? No, probably not. //Back to our makeshift tag "parser" we go. $state = blcUtility::extract_tags($response['body'], 'yt:state', false); if (empty($state)) { //Phew, no restrictions. $result['log'] .= __("Video OK", 'broken-link-checker'); $result['status_text'] = __('OK', 'link status', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_OK; $result['http_code'] = 0; } else { //Get the state name and code and append them to the log $state = reset($state); $state_name = $state['attributes']['name']; $state_reason = isset($state['attributes']['reasonCode']) ? $state['attributes']['reasonCode'] : ''; $result['result_hash'] = 'youtube_api|' . $state_name . '|' . $state_reason; $result['log'] .= sprintf(__('Video status : %s%s', 'broken-link-checker'), $state_name, $state_reason ? ' [' . $state_reason . ']' : ''); //A couple of restricted states are not that bad $state_ok = $state_name == 'processing' || $state_name == 'restricted' && $state_reason == 'limitedSyndication'; if ($state_ok) { $result['broken'] = false; $result['status_text'] = __('OK', 'link status', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_OK; $result['http_code'] = 0; } else { $result['broken'] = true; $result['status_text'] = __('Video Restricted', 'broken-link-checker'); $result['status_code'] = BLC_LINK_STATUS_WARNING; $result['http_code'] = 0; } } //Add the video title to the log, purely for information. //http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:title $title = blcUtility::extract_tags($response['body'], 'media:title', false); if (!empty($title)) { $result['log'] .= "\n\nTitle : \"" . $title[0]['contents'] . '"'; } break; default: $result['log'] .= $result['http_code'] . $response['response']['message']; $result['log'] .= "\n" . __('Unknown YouTube API response received.'); break; } } //The hash should contain info about all pieces of data that pertain to determining if the //link is working. $result['result_hash'] = implode('|', array('youtube', $result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', $state_name, $state_reason)); return $result; }
<?php $configuration = blc_get_configuration(); if (!function_exists('fetch_feed')) { include_once ABSPATH . WPINC . '/feed.php'; } $show_plugin_feed = $show_ame_ad = false; if (!$configuration->get('user_has_donated', false)) { if (blcUtility::constrained_hash(get_site_url() . 'y', 0, 100) < 40 && function_exists('fetch_feed')) { $show_plugin_feed = true; } else { $show_ame_ad = true; } } ?> <!-- "More plugins" RSS feed --> <?php if ($show_plugin_feed) { $feed_url = 'http://w-shadow.com/files/blc-plugin-links.rss'; $num_items = 3; $feed = fetch_feed($feed_url); if (!is_wp_error($feed)) { ?> <div id="advertising" class="postbox"> <h3 class="hndle"><?php _e('More plugins by Janis Elsts', 'broken-link-checker'); ?> </h3> <div class="inside"> <ul>
/** * Perform a HEAD request to the specified URL. * * Note : * * Since the MediaFire checker works by parsing the "Location" header, redirect following * _must_ be disabled. This can become a problem on servers where WP is forced to fall back * on using WP_Http_Fopen which ignores the 'redirection' flag. WP_Http_Fsockopen would work, * but it has the lowest priority of all transports. * * Alas, there is no way to reliably influence which transport is chosen - the WP_Http::_getTransport * function caches the available choices, so plugins can disable individual transports only during * its first run. Therefore, we must pick the best transport manually. * * @param string $url * @return array|WP_Error */ function head($url) { $conf = blc_get_configuration(); $args = array('timeout' => $conf->options['timeout'], 'redirection' => 0, '_redirection' => 0); return wp_remote_head($url, $args); }
function check($url) { $url = $this->clean_url($url); //Note : Snoopy doesn't work too well with HTTPS URLs. $result = array('broken' => false, 'timeout' => false); $log = ''; //Get the timeout setting from the BLC configuration. $conf = blc_get_configuration(); $timeout = $conf->options['timeout']; $start_time = microtime_float(); //Fetch the URL with Snoopy $snoopy = new Snoopy(); $snoopy->read_timeout = $timeout; //read timeout in seconds $snoopy->agent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"; //masquerade as IE 7 $snoopy->referer = home_url(); //valid referer helps circumvent some hotlink protection schemes $snoopy->maxlength = 1024 * 5; //load up to 5 kilobytes $snoopy->fetch($this->urlencodefix($url)); $result['request_duration'] = microtime_float() - $start_time; $result['http_code'] = $snoopy->status; //HTTP status code //Snoopy returns -100 on timeout if ($result['http_code'] == -100) { $result['http_code'] = 0; $result['timeout'] = true; } //Build the log $log .= '=== '; if ($result['http_code']) { $log .= sprintf(__('HTTP code : %d', 'broken-link-checker'), $result['http_code']); } else { $log .= __('(No response)', 'broken-link-checker'); } $log .= " ===\n\n"; if ($snoopy->error) { $log .= $snoopy->error . "\n"; } if ($snoopy->timed_out) { $log .= __("Request timed out.", 'broken-link-checker') . "\n"; $result['timeout'] = true; } if (is_array($snoopy->headers)) { $log .= implode("", $snoopy->headers) . "\n"; } //those headers already contain newlines //Redirected? if ($snoopy->lastredirectaddr) { $result['final_url'] = $snoopy->lastredirectaddr; $result['redirect_count'] = $snoopy->_redirectdepth; } else { $result['final_url'] = $url; } //Determine if the link counts as "broken" $result['broken'] = $this->is_error_code($result['http_code']) || $result['timeout']; $log .= "<em>(" . __('Using Snoopy', 'broken-link-checker') . ")</em>"; $result['log'] = $log; //The hash should contain info about all pieces of data that pertain to determining if the //link is working. $result['result_hash'] = implode('|', array($result['http_code'], $result['broken'] ? 'broken' : '0', $result['timeout'] ? 'timeout' : '0', md5($result['final_url']))); return $result; }