Example #1
0
 /**
  * blcUtility::normalize_url()
  *
  * @param string $url
  * @params string $base_url (Optional) The base URL is used to convert a relative URL to a fully-qualified one
  * @return string A normalized URL or FALSE if the URL is invalid
  */
 function normalize_url($url, $base_url = '')
 {
     //Sometimes links may contain shortcodes. Parse them.
     $url = do_shortcode($url);
     $parts = @parse_url($url);
     if (!$parts) {
         return false;
     }
     //Invalid URL
     if (isset($parts['scheme'])) {
         //Only HTTP(S) links are checked. Other protocols are not supported.
         if ($parts['scheme'] != 'http' && $parts['scheme'] != 'https') {
             return false;
         }
     }
     $url = html_entity_decode($url);
     $url = preg_replace(array('/([\\?&]PHPSESSID=\\w+)$/i', '/(#[^\\/]*)$/', '/&/', '/^(javascript:.*)/i', '/([\\?&]sid=\\w+)$/i'), array('', '', '&', '', ''), $url);
     $url = trim($url);
     if ($url == '') {
         return false;
     }
     // turn relative URLs into absolute URLs
     if (empty($base_url)) {
         $base_url = get_option('siteurl');
     }
     $url = blcUtility::relative2absolute($base_url, $url);
     return $url;
 }
Example #2
0
 /**
  * Extract embedded elements from a HTML string.
  * 
  * Returns an array of IFrame elements found in the input string. 
  * Elements without a 'src' attribute are skipped. 
  * 
  * Each array item has the same basic structure as the array items
  * returned by blcUtility::extract_tags(), plus an additional 'embed_code' key 
  * that contains the full HTML code for the entire <ifram> tag.  
  *  
  * @uses blcUtility::extract_tags() This function is a simple wrapper around extract_tags()
  * 
  * @param string $html
  * @return array 
  */
 function extract_embeds($html)
 {
     $results = array();
     //remove all <code></code> blocks first
     $html = preg_replace('/<code[^>]*>.+?<\\/code>/si', ' ', $html);
     //Find likely-looking <object> elements
     $iframes = blcUtility::extract_tags($html, 'iframe', false, true);
     foreach ($iframes as $embed) {
         if (empty($embed['attributes']['src'])) {
             continue;
         }
         $embed['embed_code'] = $embed['full_tag'];
         $results[] = $embed;
     }
     return $results;
 }
Example #3
0
$moduleManager->plugin_activated();
blc_got_unsynched_items();
$blclog->info(sprintf('--- Total: %.3f seconds', microtime(true) - $notification_start));
//Turn off load limiting if it's not available on this server.
$blclog->info('Updating server load limit settings...');
$load = blcUtility::get_server_load();
if (empty($load)) {
    $blc_config_manager->options['enable_load_limit'] = false;
    $blclog->info('Disable load limit. Cannot retrieve current load average.');
} elseif ($blc_config_manager->options['enable_load_limit'] && !isset($blc_config_manager->options['server_load_limit'])) {
    $fifteen_minutes = floatval(end($load));
    $default_load_limit = round(max(min($fifteen_minutes * 2, $fifteen_minutes + 2), 4));
    $blc_config_manager->options['server_load_limit'] = $default_load_limit;
    $blclog->info(sprintf('Set server load limit to %.2f. Current load average is %.2f', $default_load_limit, $fifteen_minutes));
}
//And optimize my DB tables, too (for good measure)
$blclog->info('Optimizing the database...');
$optimize_start = microtime(true);
blcUtility::optimize_database();
$blclog->info(sprintf('--- Total: %.3f seconds', microtime(true) - $optimize_start));
$blclog->info('Completing installation...');
$blc_config_manager->options['installation_complete'] = true;
$blc_config_manager->options['installation_flag_set_on'] = date('c') . ' (' . microtime(true) . ')';
if ($blc_config_manager->save_options()) {
    $blclog->info('Configuration saved.');
} else {
    $blclog->error('Error saving plugin configuration!');
}
$blclog->info(sprintf('Installation/update completed at %s with %d queries executed.', date_i18n('Y-m-d H:i:s'), $wpdb->num_queries - $queryCnt));
$blclog->info(sprintf('Total time: %.3f seconds', microtime(true) - $activation_start));
$blclog->save();
Example #4
0
 function build_instance_list_for_email($instances, $max_displayed_links = 5)
 {
     $result = '';
     if (count($instances) > $max_displayed_links) {
         $line = sprintf(_n("Here's a list of the first %d broken links:", "Here's a list of the first %d broken links:", $max_displayed_links, 'broken-link-checker'), $max_displayed_links);
     } else {
         $line = __("Here's a list of the new broken links: ", 'broken-link-checker');
     }
     $result .= "<p>{$line}</p>";
     //Show up to $max_displayed_links broken link instances right in the email.
     $displayed = 0;
     foreach ($instances as $instance) {
         /* @var blcLinkInstance $instance */
         $pieces = array(sprintf(__('Link text : %s', 'broken-link-checker'), $instance->ui_get_link_text('email')), sprintf(__('Link URL : <a href="%s">%s</a>', 'broken-link-checker'), htmlentities($instance->get_url()), blcUtility::truncate($instance->get_url(), 70, '')), sprintf(__('Source : %s', 'broken-link-checker'), $instance->ui_get_source('email')));
         $link_entry = implode("<br>", $pieces);
         $result .= "{$link_entry}<br><br>";
         $displayed++;
         if ($displayed >= $max_displayed_links) {
             break;
         }
     }
     //Add a link to the "Broken Links" tab.
     $result .= __("You can see all broken links here:", 'broken-link-checker') . "<br>";
     $result .= sprintf('<a href="%1$s">%1$s</a>', admin_url('tools.php?page=view-broken-links'));
     return $result;
 }
Example #5
0
 /**
  * Get the link URL in ASCII-compatible encoding.
  * 
  * @return string
  */
 function get_ascii_url()
 {
     return blcUtility::idn_to_ascii($this->url);
 }
 function ui_get_source($container_field = '', $context = 'display')
 {
     //Display a comment icon.
     if ($container_field == 'comment_author_url') {
         $image = 'font-awesome/font-awesome-user.png';
     } else {
         $image = 'font-awesome/font-awesome-comment-alt.png';
     }
     $image = sprintf('<img src="%s/broken-link-checker/images/%s" class="blc-small-image" title="%3$s" alt="%3$s"> ', WP_PLUGIN_URL, $image, __('Comment', 'broken-link-checker'));
     $comment = $this->get_wrapped_object();
     //Display a small text sample from the comment
     $text_sample = strip_tags($comment->comment_content);
     $text_sample = blcUtility::truncate($text_sample, 65);
     $html = sprintf('<a href="%s" title="%s"><b>%s</b> &mdash; %s</a>', $this->get_edit_url(), esc_attr__('Edit comment'), esc_attr($comment->comment_author), $text_sample);
     //Don't show the image in email notifications.
     if ($context != 'email') {
         $html = $image . $html;
     }
     return $html;
 }
Example #7
0
 function check($url, $use_get = false)
 {
     $this->last_headers = '';
     $url = $this->clean_url($url);
     $result = array('broken' => false);
     $log = '';
     //Get the BLC configuration. It's used below to set the right timeout values and such.
     $conf = blc_get_configuration();
     //Init curl.
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $this->urlencodefix($url));
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     //Masquerade as Internet explorer
     //$ua = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';
     $ua = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)';
     curl_setopt($ch, CURLOPT_USERAGENT, $ua);
     //Add a semi-plausible referer header to avoid tripping up some bot traps
     curl_setopt($ch, CURLOPT_REFERER, home_url());
     //Redirects don't work when safe mode or open_basedir is enabled.
     if (!blcUtility::is_safe_mode() && !blcUtility::is_open_basedir()) {
         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
     }
     //Set maximum redirects
     curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
     //Set the timeout
     curl_setopt($ch, CURLOPT_TIMEOUT, $conf->options['timeout']);
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $conf->options['timeout']);
     //Set the proxy configuration. The user can provide this in wp-config.php
     if (defined('WP_PROXY_HOST')) {
         curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
     }
     if (defined('WP_PROXY_PORT')) {
         curl_setopt($ch, CURLOPT_PROXYPORT, WP_PROXY_PORT);
     }
     if (defined('WP_PROXY_USERNAME')) {
         $auth = WP_PROXY_USERNAME;
         if (defined('WP_PROXY_PASSWORD')) {
             $auth .= ':' . WP_PROXY_PASSWORD;
         }
         curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
     }
     //Make CURL return a valid result even if it gets a 404 or other error.
     curl_setopt($ch, CURLOPT_FAILONERROR, false);
     $nobody = !$use_get;
     //Whether to send a HEAD request (the default) or a GET request
     $parts = @parse_url($url);
     if ($parts['scheme'] == 'https') {
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
         //Required to make HTTPS URLs work.
         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
         $nobody = false;
         //Can't use HEAD with HTTPS.
     }
     if ($nobody) {
         //If possible, use HEAD requests for speed.
         curl_setopt($ch, CURLOPT_NOBODY, true);
     } else {
         //If we must use GET at least limit the amount of downloaded data.
         curl_setopt($ch, CURLOPT_HTTPHEADER, array('Range: bytes=0-2048'));
         //2 KB
     }
     //Register a callback function which will process the HTTP header(s).
     //It can be called multiple times if the remote server performs a redirect.
     curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, 'read_header'));
     //Execute the request
     $start_time = microtime_float();
     curl_exec($ch);
     $measured_request_duration = microtime_float() - $start_time;
     $info = curl_getinfo($ch);
     //Store the results
     $result['http_code'] = intval($info['http_code']);
     $result['final_url'] = $info['url'];
     $result['request_duration'] = $info['total_time'];
     $result['redirect_count'] = $info['redirect_count'];
     //CURL doesn't return a request duration when a timeout happens, so we measure it ourselves.
     //It is useful to see how long the plugin waited for the server to respond before assuming it timed out.
     if (empty($result['request_duration'])) {
         $result['request_duration'] = $measured_request_duration;
     }
     //Determine if the link counts as "broken"
     if ($result['http_code'] == 0) {
         $result['broken'] = true;
         $error_code = curl_errno($ch);
         $log .= sprintf("%s [Error #%d]\n", curl_error($ch), $error_code);
         //We only handle a couple of CURL error codes; most are highly esoteric.
         //libcurl "CURLE_" constants can't be used here because some of them have
         //different names or values in PHP.
         switch ($error_code) {
             case 6:
                 //CURLE_COULDNT_RESOLVE_HOST
                 $result['status_code'] = BLC_LINK_STATUS_WARNING;
                 $result['status_text'] = __('Server Not Found', 'broken-link-checker');
                 break;
             case 28:
                 //CURLE_OPERATION_TIMEDOUT
                 $result['timeout'] = true;
                 break;
             case 7:
                 //CURLE_COULDNT_CONNECT
                 //More often than not, this error code indicates that the connection attempt
                 //timed out. This heuristic tries to distinguish between connections that fail
                 //due to timeouts and those that fail due to other causes.
                 if ($result['request_duration'] >= 0.9 * $conf->options['timeout']) {
                     $result['timeout'] = true;
                 } else {
                     $result['status_code'] = BLC_LINK_STATUS_WARNING;
                     $result['status_text'] = __('Connection Failed', 'broken-link-checker');
                 }
                 break;
             default:
                 $result['status_code'] = BLC_LINK_STATUS_WARNING;
                 $result['status_text'] = __('Unknown Error', 'broken-link-checker');
         }
     } else {
         $result['broken'] = $this->is_error_code($result['http_code']);
     }
     curl_close($ch);
     if ($nobody && $result['broken']) {
         //The site in question might be expecting GET instead of HEAD, so lets retry the request
         //using the GET verb.
         return $this->check($url, true);
         //Note : normally a server that doesn't allow HEAD requests on a specific resource *should*
         //return "405 Method Not Allowed". Unfortunately, there are sites that return 404 or
         //another, even more general, error code instead. So just checking for 405 wouldn't be enough.
     }
     //When safe_mode or open_basedir is enabled CURL will be forbidden from following redirects,
     //so redirect_count will be 0 for all URLs. As a workaround, set it to 1 when the HTTP
     //response codes indicates a redirect but redirect_count is zero.
     //Note to self : Extracting the Location header might also be helpful.
     if ($result['redirect_count'] == 0 && in_array($result['http_code'], array(301, 302, 303, 307))) {
         $result['redirect_count'] = 1;
     }
     //Build the log from HTTP code and headers.
     $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";
     $log .= $this->last_headers;
     if (!empty($result['broken']) && !empty($result['timeout'])) {
         $log .= "\n(" . __("Most likely the connection timed out or the domain doesn't exist.", 'broken-link-checker') . ')';
     }
     $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'], !empty($result['broken']) ? 'broken' : '0', !empty($result['timeout']) ? 'timeout' : '0', md5($result['final_url'])));
     return $result;
 }
 /**
  * Apply a callback function to all HTML links found in a string and return the results.
  *
  * The link data array will contain at least these keys :
  *  'href' - the URL of the link (with htmlentitydecode() already applied).
  *  '#raw' - the raw link code, e.g. the entire '<a href="...">...</a>' tag of a HTML link.
  *  '#offset' - the offset within $content at which the first character of the link tag was found.
  *  '#link_text' - the link's anchor text, if any. May contain HTML tags.
  * 
  * Any attributes of the link tag will also be included in the returned array as attr_name => attr_value
  * pairs. This function will also automatically decode any HTML entities found in attribute values.   
  *
  * @see blcParser::map()
  *
  * @param string $content A text string to parse for links. 
  * @param callback $callback Callback function to apply to all found links.  
  * @param mixed $extra If the optional $extra param. is supplied, it will be passed as the second parameter to the function $callback. 
  * @return array An array of all detected links after applying $callback to each of them.
  */
 function map($content, $callback, $extra = null)
 {
     $results = array();
     //Find all links
     $links = blcUtility::extract_tags($content, 'a', false, true);
     //Iterate over the links and apply $callback to each
     foreach ($links as $link) {
         //Massage the found link into a form required for the callback function
         $param = $link['attributes'];
         $param = array_merge($param, array('#raw' => $link['full_tag'], '#offset' => $link['offset'], '#link_text' => $link['contents'], 'href' => isset($link['attributes']['href']) ? $link['attributes']['href'] : ''));
         //Prepare arguments for the callback
         $params = array($param);
         if (isset($extra)) {
             $params[] = $extra;
         }
         //Execute & store :)
         $results[] = call_user_func_array($callback, $params);
     }
     return $results;
 }
Example #9
0
 /**
  * Convert an internationalized domain name (or URL) from ASCII-compatible encoding to UTF8.
  * 
  * @param string $url
  * @return string
  */
 static function idn_to_utf8($url)
 {
     $idn = blcUtility::get_idna_converter();
     if ($idn != null) {
         $url = $idn->decode($url);
     }
     return $url;
 }
Example #10
0
 function check($url, $use_get = false)
 {
     $this->last_headers = '';
     $url = $this->clean_url($url);
     $result = array('broken' => false);
     $log = '';
     //Get the BLC configuration. It's used below to set the right timeout values and such.
     $conf = blc_get_configuration();
     //Init curl.
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_URL, $this->urlencodefix($url));
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
     //Masquerade as Internet explorer
     //$ua = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)';
     $ua = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)';
     curl_setopt($ch, CURLOPT_USERAGENT, $ua);
     //Add a semi-plausible referer header to avoid tripping up some bot traps
     curl_setopt($ch, CURLOPT_REFERER, get_option('home'));
     //Redirects don't work when safe mode or open_basedir is enabled.
     if (!blcUtility::is_safe_mode() && !blcUtility::is_open_basedir()) {
         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
     }
     //Set maximum redirects
     curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
     //Set the timeout
     curl_setopt($ch, CURLOPT_TIMEOUT, $conf->options['timeout']);
     //Set the proxy configuration. The user can provide this in wp-config.php
     if (defined('WP_PROXY_HOST')) {
         curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
     }
     if (defined('WP_PROXY_PORT')) {
         curl_setopt($ch, CURLOPT_PROXYPORT, WP_PROXY_PORT);
     }
     if (defined('WP_PROXY_USERNAME')) {
         $auth = WP_PROXY_USERNAME;
         if (defined('WP_PROXY_PASSWORD')) {
             $auth .= ':' . WP_PROXY_PASSWORD;
         }
         curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
     }
     //Make CURL return a valid result even if it gets a 404 or other error.
     curl_setopt($ch, CURLOPT_FAILONERROR, false);
     $nobody = !$use_get;
     //Whether to send a HEAD request (the default) or a GET request
     $parts = @parse_url($url);
     if ($parts['scheme'] == 'https') {
         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
         //Required to make HTTPS URLs work.
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
         //Likewise.
         $nobody = false;
         //Can't use HEAD with HTTPS.
     }
     if ($nobody) {
         //If possible, use HEAD requests for speed.
         curl_setopt($ch, CURLOPT_NOBODY, true);
     } else {
         //If we must use GET at least limit the amount of downloaded data.
         curl_setopt($ch, CURLOPT_HTTPHEADER, array('Range: bytes=0-2048'));
         //2 KB
     }
     //Register a callback function which will process the HTTP header(s).
     //It can be called multiple times if the remote server performs a redirect.
     curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, 'read_header'));
     //Execute the request
     curl_exec($ch);
     $info = curl_getinfo($ch);
     curl_close($ch);
     //Store the results
     $result['http_code'] = intval($info['http_code']);
     $result['timeout'] = $result['http_code'] == 0;
     //If the code is 0 then it's probably a timeout
     $result['final_url'] = $info['url'];
     $result['request_duration'] = $info['total_time'];
     $result['redirect_count'] = $info['redirect_count'];
     //Determine if the link counts as "broken"
     $result['broken'] = $this->is_error_code($result['http_code']) || $result['timeout'];
     if ($nobody && $result['broken']) {
         //The site in question might be expecting GET instead of HEAD, so lets retry the request
         //using the GET verb.
         return $this->check($url, true);
         //Note : normally a server that doesn't allow HEAD requests on a specific resource *should*
         //return "405 Method Not Allowed". Unfortunately, there are sites that return 404 or
         //another, even more general, error code instead. So just checking for 405 wouldn't be enough.
     }
     //When safe_mode or open_basedir is enabled CURL will be forbidden from following redirects,
     //so redirect_count will be 0 for all URLs. As a workaround, set it to 1 when the HTTP
     //response codes indicates a redirect but redirect_count is zero.
     //Note to self : Extracting the Location header might also be helpful.
     if ($result['redirect_count'] == 0 && in_array($result['http_code'], array(301, 302, 303, 307))) {
         $result['redirect_count'] = 1;
     }
     //Build the log from HTTP code and headers.
     //TODO: Put some kind of a color-coded error explanation at the top of the log, not a cryptic HTTP code.
     $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";
     $log .= $this->last_headers;
     if ($result['broken'] && $result['timeout']) {
         $log .= "\n(" . __("Most likely the connection timed out or the domain doesn't exist.", 'broken-link-checker') . ')';
     }
     $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;
 }
 function ui_get_source_comment($container, $container_field = '')
 {
     //Display a comment icon.
     if ($container_field == 'comment_author_url') {
         $image = 'font-awesome/font-awesome-user.png';
     } else {
         $image = 'font-awesome/font-awesome-comment-alt.png';
     }
     $comment = $container->get_wrapped_object();
     //Display a small text sample from the comment
     $text_sample = strip_tags($comment->comment_content);
     $text_sample = blcUtility::truncate($text_sample, 65);
     return array('image' => $image, 'text_sample' => $text_sample, 'comment_author' => esc_attr($comment->comment_author), 'comment_id' => esc_attr($comment->comment_ID), 'comment_status' => wp_get_comment_status($comment->comment_ID), 'container_post_title' => get_the_title($comment->comment_post_ID), 'container_post_status' => get_post_status($comment->comment_post_ID), 'container_post_ID' => $comment->comment_post_ID);
 }
 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;
 }
 /**
  * Check a YouTube API response that contains a single playlist.
  *
  * @param array $response
  * @param array $result
  * @return array
  */
 protected function check_playlist($response, $result)
 {
     switch ($result['http_code']) {
         case 404:
             //Not found
             $result['log'] .= __('Playlist Not Found', 'broken-link-checker');
             $result['broken'] = true;
             $result['http_code'] = 0;
             $result['status_text'] = __('Playlist Not Found', 'broken-link-checker');
             $result['status_code'] = BLC_LINK_STATUS_ERROR;
             break;
         case 403:
             //Forbidden. We're unlikely to see this code for playlists, but lets allow it.
             $result['log'] .= $response['body'];
             $result['broken'] = true;
             $result['status_text'] = __('Playlist Restricted', 'broken-link-checker');
             $result['status_code'] = BLC_LINK_STATUS_ERROR;
             break;
         case 400:
             //Bad request. Probably indicates a client error (invalid API request). Body contains details.
             $result['log'] .= $response['body'];
             $result['broken'] = true;
             $result['status_text'] = __('Invalid Playlist', 'broken-link-checker');
             $result['status_code'] = BLC_LINK_STATUS_WARNING;
             break;
         case 200:
             //The playlist exists, but some of the videos may be restricted.
             //Check for <yt:state> tags.
             $video_states = blcUtility::extract_tags($response['body'], 'yt:state', false);
             if (empty($video_states)) {
                 //No restrictions. Does the playlist have any entries?
                 $entries = blcUtility::extract_tags($response['body'], 'entry', false);
                 if (!empty($entries)) {
                     //All is well.
                     $result['log'] .= __("Playlist 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 {
                     //An empty playlist. It is possible that all of the videos
                     //have been deleted. Treat it as a warning.
                     $result['log'] .= __("This playlist has no entries or all entries have been deleted.", 'broken-link-checker');
                     $result['status_text'] = __('Empty Playlist', 'link status', 'broken-link-checker');
                     $result['status_code'] = BLC_LINK_STATUS_WARNING;
                     $result['http_code'] = 0;
                     $result['broken'] = true;
                 }
             } else {
                 //Treat the playlist as broken if at least one video is inaccessible.
                 foreach ($video_states as $state) {
                     $state_name = $state['attributes']['name'];
                     $state_reason = isset($state['attributes']['reasonCode']) ? $state['attributes']['reasonCode'] : '';
                     if (!$this->is_state_ok($state_name, $state_reason)) {
                         $result['log'] .= sprintf(__('Video status : %s%s', 'broken-link-checker'), $state_name, $state_reason ? ' [' . $state_reason . ']' : '');
                         $result['state_name'] = $state_name;
                         $result['state_reason'] = $state_reason;
                         $result['broken'] = true;
                         $result['status_text'] = __('Video Restricted', 'broken-link-checker');
                         $result['status_code'] = BLC_LINK_STATUS_WARNING;
                         $result['http_code'] = 0;
                         break;
                     }
                 }
                 if (!$result['broken']) {
                     $result['status_text'] = __('OK', 'link status', 'broken-link-checker');
                     $result['status_code'] = BLC_LINK_STATUS_OK;
                     $result['http_code'] = 0;
                 }
             }
             //Add the playlist title to the log, purely for information.
             $title = blcUtility::extract_tags($response['body'], 'title', false);
             if (!empty($title)) {
                 $result['log'] .= "\n\nPlaylist title : \"" . $title[0]['contents'] . '"';
             }
             break;
         default:
             $result['log'] .= $result['http_code'] . $response['response']['message'];
             $result['log'] .= "\n" . __('Unknown YouTube API response received.');
             break;
     }
     return $result;
 }
 function send_email_notifications()
 {
     global $wpdb;
     //Find links that have been detected as broken since the last sent notification.
     $last_notification = date('Y-m-d H:i:s', $this->conf->options['last_notification_sent']);
     $where = $wpdb->prepare('( first_failure >= %s )', $last_notification);
     $links = blc_get_links(array('s_filter' => 'broken', 'where_expr' => $where, 'load_instances' => true, 'max_results' => 0));
     if (empty($links)) {
         return;
     }
     $cnt = count($links);
     //Prepare email message
     $subject = sprintf(__("[%s] Broken links detected", 'broken-link-checker'), html_entity_decode(get_option('blogname'), ENT_QUOTES));
     $body = sprintf(_n("Broken Link Checker has detected %d new broken link on your site.", "Broken Link Checker has detected %d new broken links on your site.", $cnt, 'broken-link-checker'), $cnt);
     $body .= "<br>";
     $max_displayed_links = 5;
     if ($cnt > $max_displayed_links) {
         $line = sprintf(_n("Here's a list of the first %d broken links:", "Here's a list of the first %d broken links:", $max_displayed_links, 'broken-link-checker'), $max_displayed_links);
     } else {
         $line = __("Here's a list of the new broken links: ", 'broken-link-checker');
     }
     $body .= "<p>{$line}</p>";
     //Show up to $max_displayed_links broken link instances right in the email.
     $displayed = 0;
     foreach ($links as $link) {
         $instances = $link->get_instances();
         foreach ($instances as $instance) {
             $pieces = array(sprintf(__('Link text : %s', 'broken-link-checker'), $instance->ui_get_link_text('email')), sprintf(__('Link URL : <a href="%s">%s</a>', 'broken-link-checker'), htmlentities($link->url), blcUtility::truncate($link->url, 70, '')), sprintf(__('Source : %s', 'broken-link-checker'), $instance->ui_get_source('email')));
             $link_entry = implode("<br>", $pieces);
             $body .= "{$link_entry}<br><br>";
             $displayed++;
             if ($displayed >= $max_displayed_links) {
                 break 2;
                 //Exit both foreach loops
             }
         }
     }
     //Add a link to the "Broken Links" tab.
     $body .= __("You can see all broken links here:", 'broken-link-checker') . "<br>";
     $link_page = admin_url('tools.php?page=view-broken-links');
     $body .= sprintf('<a href="%1$s">%1$s</a>', $link_page);
     //Need to override the default 'text/plain' content type to send a HTML email.
     add_filter('wp_mail_content_type', array(&$this, 'override_mail_content_type'));
     //Send the notification
     $rez = wp_mail(get_option('admin_email'), $subject, $body);
     if ($rez) {
         $this->conf->options['last_notification_sent'] = time();
         $this->conf->save_options();
     }
     //Remove the override so that it doesn't interfere with other plugins that might
     //want to send normal plaintext emails.
     remove_filter('wp_mail_content_type', array(&$this, 'override_mail_content_type'));
 }
Example #15
0
        ?>
		</ul>
	</div>
</div>
<?php 
    }
}
?>

<!-- Admin Menu Editor Pro ad -->
<?php 
if ($show_ame_ad) {
    //Display an ad for Admin Menu Editor.
    //We're A/B testing a bunch of different ad copies.
    $ame_copy_variants = array(array('a', "Add, delete, hide, or move any admin menu item."), array('b', "Organize your admin menu the way you want it."), array('c', "Hide, move or customize admin menus. Perfect for client sites."));
    $ad_copy_index = intval(blcUtility::constrained_hash(get_site_url(), 0, count($ame_copy_variants)));
    $ad_copy = $ame_copy_variants[$ad_copy_index];
    $ad_url = sprintf('http://w-shadow.com/admin-menu-editor-pro/?utm_source=broken_link_checker&utm_medium=text_link&utm_campaign=Plugins&utm_content=%s', urlencode('ad_copy_') . $ad_copy[0]);
    ?>
<div class="postbox" id="advertising">
	<h3 class="hndle"><?php 
    _e('More plugins by Janis Elsts', 'broken-link-checker');
    ?>
</h3>
	<div class="inside">
		<p class="ws-ame-ad-copy"><?php 
    echo $ad_copy[1];
    ?>
</p>
		<p class="ws-ame-ad-link">
			<a href="<?php 
 /**
  * Extract embedded elements from a HTML string.
  * 
  * This function returns an array of <embed> elements found in the input
  * string. Embeds without a 'src' attribute are skipped.
  * 
  * Each array item has the same basic structure as the array items
  * returned by blcUtility::extract_tags(), plus an additional 'embed_code' key 
  * that contains the HTML code for the element. If the embed element is wrapped
  * in an <object>, the 'embed_code' key contains the full HTML for the entire
  * <object> + <embed> structure.
  *  
  * @uses blcUtility::extract_tags() This function is a simple wrapper around extract_tags()
  * 
  * @param string $html
  * @return array 
  */
 function extract_embeds($html)
 {
     $results = array();
     //remove all <code></code> blocks first
     $html = preg_replace('/<code[^>]*>.+?<\\/code>/si', ' ', $html);
     //Find likely-looking <object> elements
     $objects = blcUtility::extract_tags($html, 'object', false, true);
     foreach ($objects as $candidate) {
         //Find the <embed> tag
         $embed = blcUtility::extract_tags($candidate['full_tag'], 'embed', true);
         if (empty($embed)) {
             continue;
         }
         $embed = reset($embed);
         //Take the first (and only) found <embed> element
         if (empty($embed['attributes']['src'])) {
             continue;
         }
         $embed['embed_code'] = $candidate['full_tag'];
         $results[] = $embed;
         //Remove the element so it doesn't come up when we search for plain <embed> elements.
         $html = str_replace($candidate['full_tag'], ' ', $html);
     }
     //Find <embed> elements not wrapped in an <object> element.
     $embeds = blcUtility::extract_tags($html, 'embed', false, true);
     foreach ($embeds as $embed) {
         if (!empty($embed['attributes']['src'])) {
             $embed['embed_code'] = $embed['full_tag'];
             $results[] = $embed;
         }
     }
     return $results;
 }
        /**
         * @param blcLink $link
         * @param blcLinkInstance[] $instances
         */
        function column_status($link, $instances)
        {
            printf('<table class="mini-status" title="%s">', esc_attr(__('Show more info about this link', 'broken-link-checker')));
            $status = $link->analyse_status();
            printf('<tr class="link-status-row link-status-%s">
				<td>
					<span class="http-code">%s</span> <span class="status-text">%s</span>
				</td>
			</tr>', $status['code'], empty($link->http_code) ? '' : $link->http_code, $status['text']);
            //Last checked...
            if ($link->last_check != 0) {
                $last_check = _x('Checked', 'checked how long ago', 'broken-link-checker') . ' ';
                $last_check .= blcUtility::fuzzy_delta(time() - $link->last_check, 'ago');
                printf('<tr class="link-last-checked"><td>%s</td></tr>', $last_check);
            }
            //Broken for...
            if ($link->broken) {
                $delta = time() - $link->first_failure;
                $broken_for = blcUtility::fuzzy_delta($delta);
                printf('<tr class="link-broken-for"><td>%s %s</td></tr>', __('Broken for', 'broken-link-checker'), $broken_for);
            }
            echo '</table>';
        }