Version Description
Download this release
Release Info
| Developer | whiteshadow |
| Plugin | |
| Version | 0.5.10 |
| Comparing to | |
| See all releases | |
Code changes from version 0.5.9 to 0.5.10
- broken-link-checker.php +62 -2177
- config-manager.php +85 -0
- core.php +2137 -0
- highlighter-class.php +76 -0
- link-classes.php +12 -10
- readme.txt +17 -2
- utility-class.php +31 -15
broken-link-checker.php
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
<?php
|
|
|
|
| 2 |
/*
|
| 3 |
Plugin Name: Broken Link Checker
|
| 4 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
| 5 |
Description: Checks your posts for broken links and missing images and notifies you on the dashboard if any are found.
|
| 6 |
-
Version: 0.5.
|
| 7 |
Author: Janis Elsts
|
| 8 |
Author URI: http://w-shadow.com/blog/
|
| 9 |
*/
|
|
@@ -13,33 +14,6 @@ Created by Janis Elsts (email : whiteshadow@w-shadow.com)
|
|
| 13 |
MySQL 4.0 compatibility by Jeroen (www.yukka.eu)
|
| 14 |
*/
|
| 15 |
|
| 16 |
-
//The plugin will use Snoopy in case CURL is not available
|
| 17 |
-
if (!class_exists('Snoopy')) require_once(ABSPATH.'/wp-includes/class-snoopy.php');
|
| 18 |
-
|
| 19 |
-
/**
|
| 20 |
-
* Simple function to replicate PHP 5 behaviour
|
| 21 |
-
*/
|
| 22 |
-
if ( !function_exists('microtime_float') ) {
|
| 23 |
-
function microtime_float()
|
| 24 |
-
{
|
| 25 |
-
list($usec, $sec) = explode(" ", microtime());
|
| 26 |
-
return ((float)$usec + (float)$sec);
|
| 27 |
-
}
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
//Make sure some useful constants are defined
|
| 31 |
-
if ( ! defined( 'WP_CONTENT_URL' ) )
|
| 32 |
-
define( 'WP_CONTENT_URL', get_option( 'siteurl' ) . '/wp-content' );
|
| 33 |
-
if ( ! defined( 'WP_CONTENT_DIR' ) )
|
| 34 |
-
define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
|
| 35 |
-
if ( ! defined( 'WP_PLUGIN_URL' ) )
|
| 36 |
-
define( 'WP_PLUGIN_URL', WP_CONTENT_URL. '/plugins' );
|
| 37 |
-
if ( ! defined( 'WP_PLUGIN_DIR' ) )
|
| 38 |
-
define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
|
| 39 |
-
|
| 40 |
-
define('BLC_CHECKING', 1);
|
| 41 |
-
define('BLC_TIMEOUT', 2);
|
| 42 |
-
|
| 43 |
/*
|
| 44 |
//FirePHP for debugging
|
| 45 |
if ( !class_exists('FB') ) {
|
|
@@ -51,2156 +25,67 @@ if ( !class_exists('FB') ) {
|
|
| 51 |
//to uncomment : \/\/(\s*FB::) -> $1
|
| 52 |
//*/
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
var $myfile=''; //should be removed
|
| 64 |
-
var $myfolder=''; //should be removed
|
| 65 |
-
var $mybasename=''; //should be removed
|
| 66 |
-
var $siteurl; //should be removed
|
| 67 |
-
var $defaults;
|
| 68 |
-
var $db_version = 1;
|
| 69 |
-
|
| 70 |
-
var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
|
| 71 |
-
var $lockfile_handle = null;
|
| 72 |
-
|
| 73 |
-
function ws_broken_link_checker() {
|
| 74 |
-
global $wpdb;
|
| 75 |
-
|
| 76 |
-
//set default options
|
| 77 |
-
$this->defaults = array(
|
| 78 |
-
'max_execution_time' => 5*60, //How long the worker instance may run, at most.
|
| 79 |
-
'check_threshold' => 72, //Check each link every 72 hours.
|
| 80 |
-
'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
|
| 81 |
-
'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
|
| 82 |
-
'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
|
| 83 |
-
'recheck_count' => 3, //[Internal] How many times a broken link should be re-checked (slightly buggy)
|
| 84 |
-
|
| 85 |
-
//These three are currently ignored. Everything is checked by default.
|
| 86 |
-
'check_posts' => true,
|
| 87 |
-
'check_custom_fields' => true,
|
| 88 |
-
'check_blogroll' => true,
|
| 89 |
-
|
| 90 |
-
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
| 91 |
-
|
| 92 |
-
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
| 93 |
-
|
| 94 |
-
'need_resynch' => false, //[Internal flag]
|
| 95 |
-
|
| 96 |
-
'current_db_version' => 0, //The current version of the plugin's tables
|
| 97 |
-
);
|
| 98 |
-
|
| 99 |
-
$this->load_options();
|
| 100 |
-
|
| 101 |
-
$this->siteurl = get_option('siteurl');
|
| 102 |
-
|
| 103 |
-
$my_file = str_replace('\\', '/',__FILE__);
|
| 104 |
-
$my_file = preg_replace('/^.*wp-content[\\\\\/]plugins[\\\\\/]/', '', $my_file);
|
| 105 |
-
add_action('activate_' . plugin_basename(__FILE__), array(&$this,'activation'));
|
| 106 |
-
$this->myfile=$my_file;
|
| 107 |
-
$this->myfolder=basename(dirname(__FILE__));
|
| 108 |
-
$this->mybasename=plugin_basename(__FILE__);
|
| 109 |
-
|
| 110 |
-
add_action('admin_menu', array(&$this,'admin_menu'));
|
| 111 |
-
|
| 112 |
-
//These hooks update the plugin's internal records when posts are added, deleted or modified.
|
| 113 |
-
add_action('delete_post', array(&$this,'post_deleted'));
|
| 114 |
-
add_action('save_post', array(&$this,'post_saved'));
|
| 115 |
-
|
| 116 |
-
//These do the same for (blogroll) links.
|
| 117 |
-
add_action('add_link', array(&$this,'hook_add_link'));
|
| 118 |
-
add_action('edit_link', array(&$this,'hook_edit_link'));
|
| 119 |
-
add_action('delete_link', array(&$this,'hook_delete_link'));
|
| 120 |
-
|
| 121 |
-
add_action('admin_footer', array(&$this,'admin_footer'));
|
| 122 |
-
add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
|
| 123 |
-
//The dashboard widget
|
| 124 |
-
add_action('wp_dashboard_setup', array(&$this, 'hook_wp_dashboard_setup'));
|
| 125 |
-
|
| 126 |
-
if ( $this->options['mark_broken_links'] ){
|
| 127 |
-
add_filter( 'the_content', array(&$this,'the_content') );
|
| 128 |
-
if ( !empty($this->options['broken_link_css']) ){
|
| 129 |
-
add_action( 'wp_head', array(&$this,'header_css') );
|
| 130 |
-
}
|
| 131 |
-
}
|
| 132 |
-
|
| 133 |
-
//AJAXy hooks
|
| 134 |
-
add_action( 'wp_ajax_blc_full_status', array(&$this,'ajax_full_status') );
|
| 135 |
-
add_action( 'wp_ajax_blc_dashboard_status', array(&$this,'ajax_dashboard_status') );
|
| 136 |
-
add_action( 'wp_ajax_blc_work', array(&$this,'ajax_work') );
|
| 137 |
-
add_action( 'wp_ajax_blc_discard', array(&$this,'ajax_discard') );
|
| 138 |
-
add_action( 'wp_ajax_blc_edit', array(&$this,'ajax_edit') );
|
| 139 |
-
add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') );
|
| 140 |
-
add_action( 'wp_ajax_blc_exclude_link', array(&$this,'ajax_exclude_link') );
|
| 141 |
-
add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') );
|
| 142 |
-
}
|
| 143 |
-
|
| 144 |
-
function admin_footer(){
|
| 145 |
-
?>
|
| 146 |
-
<!-- wsblc admin footer -->
|
| 147 |
-
<div id='wsblc_updater_div'></div>
|
| 148 |
-
<script type='text/javascript'>
|
| 149 |
-
(function($){
|
| 150 |
-
|
| 151 |
-
function blcDoWork(){
|
| 152 |
-
$.post(
|
| 153 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 154 |
-
{
|
| 155 |
-
'action' : 'blc_work'
|
| 156 |
-
},
|
| 157 |
-
function (data, textStatus){
|
| 158 |
-
|
| 159 |
-
}
|
| 160 |
-
);
|
| 161 |
-
}
|
| 162 |
-
//Call it the first time
|
| 163 |
-
blcDoWork();
|
| 164 |
-
|
| 165 |
-
//Then call it periodically every X seconds
|
| 166 |
-
setInterval(blcDoWork, <?php echo (intval($this->options['max_execution_time']) + 1 )*1000; ?>);
|
| 167 |
-
|
| 168 |
-
})(jQuery);
|
| 169 |
-
</script>
|
| 170 |
-
<!-- /wsblc admin footer -->
|
| 171 |
-
<?php
|
| 172 |
-
}
|
| 173 |
-
|
| 174 |
-
function header_css(){
|
| 175 |
-
echo '<style type="text/css">',$this->options['broken_link_css'],'</style>';
|
| 176 |
-
}
|
| 177 |
-
|
| 178 |
-
function the_content($content){
|
| 179 |
-
global $post, $wpdb;
|
| 180 |
-
if ( empty($post) ) return $content;
|
| 181 |
-
|
| 182 |
-
$q = "
|
| 183 |
-
SELECT instances.link_text, links.*
|
| 184 |
-
|
| 185 |
-
FROM {$wpdb->prefix}blc_instances AS instances, {$wpdb->prefix}blc_links AS links
|
| 186 |
-
|
| 187 |
-
WHERE
|
| 188 |
-
instances.source_id = %d
|
| 189 |
-
AND instances.source_type = 'post'
|
| 190 |
-
AND instances.instance_type = 'link'
|
| 191 |
-
|
| 192 |
-
AND instances.link_id = links.link_id
|
| 193 |
-
AND links.check_count > 0
|
| 194 |
-
AND ( links.http_code < 200 OR links.http_code >= 400 OR links.timeout = 1 )";
|
| 195 |
-
|
| 196 |
-
$rows = $wpdb->get_results( $wpdb->prepare( $q, $post->ID ), ARRAY_A );
|
| 197 |
-
if( $rows ){
|
| 198 |
-
$this->links_to_remove = array();
|
| 199 |
-
foreach($rows as $row){
|
| 200 |
-
$this->links_to_remove[$row['url']] = $row;
|
| 201 |
-
}
|
| 202 |
-
$content = preg_replace_callback( blcUtility::link_pattern(), array(&$this,'mark_broken_links'), $content );
|
| 203 |
-
};
|
| 204 |
-
|
| 205 |
-
return $content;
|
| 206 |
-
}
|
| 207 |
-
|
| 208 |
-
function mark_broken_links($matches){
|
| 209 |
-
//TODO:Tooltip-style popups with more info
|
| 210 |
-
$url = blcUtility::normalize_url( html_entity_decode( $matches[3] ) );
|
| 211 |
-
if( isset( $this->links_to_remove[$url] ) ){
|
| 212 |
-
return $matches[1].$matches[2].$matches[3].$matches[2].' class="broken_link" '.$matches[4].
|
| 213 |
-
$matches[5].$matches[6];
|
| 214 |
-
} else {
|
| 215 |
-
return $matches[0];
|
| 216 |
-
}
|
| 217 |
-
}
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
function is_excluded($url){
|
| 221 |
-
if (!is_array($this->options['exclusion_list'])) return false;
|
| 222 |
-
foreach($this->options['exclusion_list'] as $excluded_word){
|
| 223 |
-
if (stristr($url, $excluded_word)){
|
| 224 |
-
return true;
|
| 225 |
-
}
|
| 226 |
-
}
|
| 227 |
-
return false;
|
| 228 |
-
}
|
| 229 |
-
|
| 230 |
-
function dashboard_widget(){
|
| 231 |
-
?>
|
| 232 |
-
<p id='wsblc_activity_box'>Loading...</p>
|
| 233 |
-
<script type='text/javascript'>
|
| 234 |
-
jQuery(function($){
|
| 235 |
-
var blc_was_autoexpanded = false;
|
| 236 |
-
|
| 237 |
-
function blcDashboardStatus(){
|
| 238 |
-
$.getJSON(
|
| 239 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 240 |
-
{
|
| 241 |
-
'action' : 'blc_dashboard_status'
|
| 242 |
-
},
|
| 243 |
-
function (data, textStatus){
|
| 244 |
-
if ( data && ( typeof(data.text) != 'undefined' ) ) {
|
| 245 |
-
$('#wsblc_activity_box').html(data.text);
|
| 246 |
-
<?php if ( $this->options['autoexpand_widget'] ) { ?>
|
| 247 |
-
//Expand the widget if there are broken links.
|
| 248 |
-
//Do this only once per pageload so as not to annoy the user.
|
| 249 |
-
if ( !blc_was_autoexpanded && ( data.status.broken_links > 0 ) ){
|
| 250 |
-
$('#blc_dashboard_widget.postbox').removeClass('closed');
|
| 251 |
-
blc_was_autoexpanded = true;
|
| 252 |
-
};
|
| 253 |
-
<?php } ?>
|
| 254 |
-
} else {
|
| 255 |
-
$('#wsblc_activity_box').html('[ Network error ]');
|
| 256 |
-
}
|
| 257 |
-
|
| 258 |
-
setTimeout( blcDashboardStatus, 120*1000 ); //...update every two minutes
|
| 259 |
-
}
|
| 260 |
-
);
|
| 261 |
-
}
|
| 262 |
-
|
| 263 |
-
blcDashboardStatus();//Call it the first time
|
| 264 |
-
|
| 265 |
-
});
|
| 266 |
-
</script>
|
| 267 |
-
<?php
|
| 268 |
-
}
|
| 269 |
-
|
| 270 |
-
function dashboard_widget_control( $widget_id, $form_inputs = array() ){
|
| 271 |
-
if ( 'POST' == $_SERVER['REQUEST_METHOD'] && 'blc_dashboard_widget' == $_POST['widget_id'] ) {
|
| 272 |
-
//It appears $form_inputs isn't used in the current WP version, so lets just use $_POST
|
| 273 |
-
$this->options['autoexpand_widget'] = !empty($_POST['blc-autoexpand']);
|
| 274 |
-
$this->save_options();
|
| 275 |
-
}
|
| 276 |
-
|
| 277 |
-
?>
|
| 278 |
-
<p><label for="blc-autoexpand">
|
| 279 |
-
<input id="blc-autoexpand" name="blc-autoexpand" type="checkbox" value="1" <?php if ( $this->options['autoexpand_widget'] ) echo 'checked="checked"'; ?> />
|
| 280 |
-
Automatically expand the widget if broken links have been detected
|
| 281 |
-
</label></p>
|
| 282 |
-
<?php
|
| 283 |
-
}
|
| 284 |
-
|
| 285 |
-
function admin_print_scripts(){
|
| 286 |
-
//jQuery is used for AJAX and effects
|
| 287 |
-
wp_enqueue_script('jquery');
|
| 288 |
-
wp_enqueue_script('jquery-ui-core');
|
| 289 |
-
}
|
| 290 |
-
|
| 291 |
-
/**
|
| 292 |
-
* ws_broken_link_checker::post_deleted()
|
| 293 |
-
* A hook for post_deleted. Remove link instances associated with that post.
|
| 294 |
-
*
|
| 295 |
-
* @param int $post_id
|
| 296 |
-
* @return void
|
| 297 |
-
*/
|
| 298 |
-
function post_deleted($post_id){
|
| 299 |
-
global $wpdb;
|
| 300 |
-
|
| 301 |
-
//FB::log($post_id, "Post deleted");
|
| 302 |
-
//Remove this post's instances
|
| 303 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 304 |
-
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
| 305 |
-
$q = $wpdb->prepare($q, intval($post_id) );
|
| 306 |
-
|
| 307 |
-
//FB::log($q, 'Executing query');
|
| 308 |
-
|
| 309 |
-
if ( $wpdb->query( $q ) === false ){
|
| 310 |
-
//FB::error($wpdb->last_error, "Database error");
|
| 311 |
-
}
|
| 312 |
-
|
| 313 |
-
//Remove the synch record
|
| 314 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_synch
|
| 315 |
-
WHERE source_id = %d AND source_type = 'post'";
|
| 316 |
-
$wpdb->query( $wpdb->prepare($q, intval($post_id)) );
|
| 317 |
-
|
| 318 |
-
//Remove any dangling link records
|
| 319 |
-
$this->cleanup_links();
|
| 320 |
-
}
|
| 321 |
-
|
| 322 |
-
function post_saved($post_id){
|
| 323 |
-
global $wpdb;
|
| 324 |
-
|
| 325 |
-
$post = get_post($post_id);
|
| 326 |
-
//Only check links in posts, not revisions and attachments
|
| 327 |
-
if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return null;
|
| 328 |
-
//Only check published posts
|
| 329 |
-
if ( $post->post_status != 'publish' ) return null;
|
| 330 |
-
|
| 331 |
-
$this->mark_unsynched( $post_id, 'post' );
|
| 332 |
-
}
|
| 333 |
-
|
| 334 |
-
function initiate_recheck(){
|
| 335 |
-
global $wpdb;
|
| 336 |
-
|
| 337 |
-
//Delete all discovered instances
|
| 338 |
-
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_instances");
|
| 339 |
-
|
| 340 |
-
//Delete all discovered links
|
| 341 |
-
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
| 342 |
-
|
| 343 |
-
//Mark all posts, custom fields and bookmarks for processing.
|
| 344 |
-
$this->resynch();
|
| 345 |
-
}
|
| 346 |
-
|
| 347 |
-
function resynch(){
|
| 348 |
-
global $wpdb;
|
| 349 |
-
|
| 350 |
-
//Drop all synchronization records
|
| 351 |
-
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch");
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
//Create new synchronization records for posts
|
| 355 |
-
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
| 356 |
-
SELECT id, 'post', 0
|
| 357 |
-
FROM {$wpdb->posts}
|
| 358 |
-
WHERE
|
| 359 |
-
{$wpdb->posts}.post_status = 'publish'
|
| 360 |
-
AND {$wpdb->posts}.post_type IN ('post', 'page')";
|
| 361 |
-
$wpdb->query( $q );
|
| 362 |
-
|
| 363 |
-
//Create new synchronization records for bookmarks (the blogroll)
|
| 364 |
-
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
| 365 |
-
SELECT link_id, 'blogroll', 0
|
| 366 |
-
FROM {$wpdb->links}
|
| 367 |
-
WHERE 1";
|
| 368 |
-
$wpdb->query( $q );
|
| 369 |
-
|
| 370 |
-
//Delete invalid instances
|
| 371 |
-
$this->cleanup_instances();
|
| 372 |
-
//Delete orphaned links
|
| 373 |
-
$this->cleanup_links();
|
| 374 |
-
|
| 375 |
-
$this->options['need_resynch'] = true;
|
| 376 |
-
$this->save_options();
|
| 377 |
-
}
|
| 378 |
-
|
| 379 |
-
function mark_unsynched( $source_id, $source_type ){
|
| 380 |
-
global $wpdb;
|
| 381 |
-
|
| 382 |
-
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
| 383 |
-
VALUES( %d, %s, %d, NOW() )";
|
| 384 |
-
$rez = $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 0 ) );
|
| 385 |
-
|
| 386 |
-
if ( !$this->options['need_resynch'] ){
|
| 387 |
-
$this->options['need_resynch'] = true;
|
| 388 |
-
$this->save_options();
|
| 389 |
-
}
|
| 390 |
-
|
| 391 |
-
return $rez;
|
| 392 |
-
}
|
| 393 |
-
|
| 394 |
-
function mark_synched( $source_id, $source_type ){
|
| 395 |
-
global $wpdb;
|
| 396 |
-
//FB::log("Marking $source_type $source_id as synched.");
|
| 397 |
-
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
| 398 |
-
VALUES( %d, %s, %d, NOW() )";
|
| 399 |
-
return $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 1 ) );
|
| 400 |
-
}
|
| 401 |
-
|
| 402 |
-
function activation(){
|
| 403 |
-
//Prepare the database.
|
| 404 |
-
$this->upgrade_database();
|
| 405 |
-
|
| 406 |
-
//Clear the instance table and mark all posts and other parse-able objects as unsynchronized.
|
| 407 |
-
$this->resynch();
|
| 408 |
-
|
| 409 |
-
//Save the default options.
|
| 410 |
-
$this->save_options();
|
| 411 |
-
}
|
| 412 |
-
|
| 413 |
-
/**
|
| 414 |
-
* ws_broken_link_checker::upgrade_database()
|
| 415 |
-
* Create and/or upgrade database tables
|
| 416 |
-
*
|
| 417 |
-
* @return void
|
| 418 |
-
*/
|
| 419 |
-
function upgrade_database(){
|
| 420 |
-
global $wpdb;
|
| 421 |
-
|
| 422 |
-
//Do we need to upgrade?
|
| 423 |
-
if ( $this->db_version == $this->options['current_db_version'] ) return;
|
| 424 |
-
|
| 425 |
-
//Delete tables used by older versions of the plugin
|
| 426 |
-
$rez = $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}blc_linkdata, {$wpdb->prefix}blc_postdata" );
|
| 427 |
-
if ( $rez === false ){
|
| 428 |
-
//FB::error($wpdb->last_error, "Database error");
|
| 429 |
-
return false;
|
| 430 |
-
}
|
| 431 |
-
|
| 432 |
-
require_once (ABSPATH . 'wp-admin/includes/upgrade.php');
|
| 433 |
-
|
| 434 |
-
//Create the link table if it doesn't exist yet.
|
| 435 |
-
$q = "CREATE TABLE {$wpdb->prefix}blc_links (
|
| 436 |
-
link_id int(20) unsigned NOT NULL auto_increment,
|
| 437 |
-
url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 438 |
-
last_check datetime NOT NULL default '0000-00-00 00:00:00',
|
| 439 |
-
check_count int(2) unsigned NOT NULL default '0',
|
| 440 |
-
final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 441 |
-
redirect_count smallint(5) unsigned NOT NULL,
|
| 442 |
-
log text NOT NULL,
|
| 443 |
-
http_code smallint(6) NOT NULL,
|
| 444 |
-
request_duration float NOT NULL default '0',
|
| 445 |
-
timeout tinyint(1) unsigned NOT NULL default '0',
|
| 446 |
-
|
| 447 |
-
PRIMARY KEY (link_id),
|
| 448 |
-
KEY url (url(150)),
|
| 449 |
-
KEY final_url (final_url(150)),
|
| 450 |
-
KEY http_code (http_code),
|
| 451 |
-
KEY timeout (timeout)
|
| 452 |
-
)";
|
| 453 |
-
dbDelta( $q );
|
| 454 |
-
|
| 455 |
-
//Fix URL fields so that they are collated as case-sensitive (this can't be done via dbDelta)
|
| 456 |
-
$wpdb->query(
|
| 457 |
-
"ALTER TABLE {$wpdb->prefix}blc_links
|
| 458 |
-
MODIFY url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 459 |
-
MODIFY final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL"
|
| 460 |
-
);
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
//Create the instance table if it doesn't exist yet.
|
| 464 |
-
$q = "CREATE TABLE {$wpdb->prefix}blc_instances (
|
| 465 |
-
instance_id int(10) unsigned NOT NULL auto_increment,
|
| 466 |
-
link_id int(10) unsigned NOT NULL,
|
| 467 |
-
source_id int(10) unsigned NOT NULL,
|
| 468 |
-
source_type enum('post','blogroll','custom_field') NOT NULL default 'post',
|
| 469 |
-
link_text varchar(250) NOT NULL,
|
| 470 |
-
instance_type enum('link','image') NOT NULL default 'link',
|
| 471 |
-
|
| 472 |
-
PRIMARY KEY (instance_id),
|
| 473 |
-
KEY link_id (link_id),
|
| 474 |
-
KEY source_id (source_id,source_type)
|
| 475 |
-
)";
|
| 476 |
-
$rez = dbDelta($q);
|
| 477 |
-
|
| 478 |
-
//....
|
| 479 |
-
$q = "CREATE TABLE {$wpdb->prefix}blc_synch (
|
| 480 |
-
source_id int(20) unsigned NOT NULL,
|
| 481 |
-
source_type enum('post','blogroll') NOT NULL,
|
| 482 |
-
synched tinyint(3) unsigned NOT NULL,
|
| 483 |
-
last_synch datetime NOT NULL,
|
| 484 |
-
PRIMARY KEY (source_id, source_type),
|
| 485 |
-
KEY synched (synched)
|
| 486 |
-
)";
|
| 487 |
-
dbDelta($q);
|
| 488 |
-
|
| 489 |
-
$this->options['current_db_version'] = $this->db_version;
|
| 490 |
-
$this->save_options();
|
| 491 |
-
}
|
| 492 |
-
|
| 493 |
-
function admin_menu(){
|
| 494 |
-
add_options_page('Link Checker Settings', 'Link Checker', 'manage_options',
|
| 495 |
-
'link-checker-settings',array(&$this, 'options_page'));
|
| 496 |
-
if (current_user_can('manage_options'))
|
| 497 |
-
add_filter('plugin_action_links', array(&$this, 'plugin_action_links'), 10, 2);
|
| 498 |
-
|
| 499 |
-
add_management_page('View Broken Links', 'Broken Links', 'edit_others_posts',
|
| 500 |
-
'view-broken-links',array(&$this, 'links_page'));
|
| 501 |
-
}
|
| 502 |
-
|
| 503 |
-
/**
|
| 504 |
-
* plugin_action_links()
|
| 505 |
-
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
| 506 |
-
* on the plugin list.
|
| 507 |
-
*
|
| 508 |
-
* @param array $links
|
| 509 |
-
* @param string $file
|
| 510 |
-
* @return array
|
| 511 |
-
*/
|
| 512 |
-
function plugin_action_links($links, $file) {
|
| 513 |
-
if ($file == $this->mybasename)
|
| 514 |
-
$links[] = "<a href='options-general.php?page=link-checker-settings'>" . __('Settings') . "</a>";
|
| 515 |
-
return $links;
|
| 516 |
-
}
|
| 517 |
-
|
| 518 |
-
function mytruncate($str, $max_length=50){
|
| 519 |
-
if(strlen($str)<=$max_length) return $str;
|
| 520 |
-
return (substr($str, 0, $max_length-3).'...');
|
| 521 |
-
}
|
| 522 |
-
|
| 523 |
-
function options_page(){
|
| 524 |
-
|
| 525 |
-
if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) {
|
| 526 |
-
$this->initiate_recheck();
|
| 527 |
-
}
|
| 528 |
-
if (isset($_GET['updated']) && ($_GET['updated'] == 'true')) {
|
| 529 |
-
if(isset($_POST['submit'])) {
|
| 530 |
-
|
| 531 |
-
$new_execution_time = intval($_POST['max_execution_time']);
|
| 532 |
-
if( $new_execution_time > 0 ){
|
| 533 |
-
$this->options['max_execution_time'] = $new_execution_time;
|
| 534 |
-
}
|
| 535 |
-
|
| 536 |
-
$new_check_threshold=intval($_POST['check_threshold']);
|
| 537 |
-
if( $new_check_threshold > 0 ){
|
| 538 |
-
$this->options['check_threshold'] = $new_check_threshold;
|
| 539 |
-
}
|
| 540 |
-
|
| 541 |
-
$this->options['mark_broken_links'] = !empty($_POST['mark_broken_links']);
|
| 542 |
-
$new_broken_link_css = trim($_POST['broken_link_css']);
|
| 543 |
-
$this->options['broken_link_css'] = $new_broken_link_css;
|
| 544 |
-
|
| 545 |
-
$this->options['exclusion_list']=array_filter( preg_split( '/[\s\r\n]+/',
|
| 546 |
-
$_POST['exclusion_list'], -1, PREG_SPLIT_NO_EMPTY ) );
|
| 547 |
-
//TODO: Maybe update affected links when exclusion list changes (expensive).
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
$new_custom_fields = array_filter( preg_split( '/[\s\r\n]+/',
|
| 551 |
-
$_POST['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY ) );
|
| 552 |
-
$diff1 = array_diff( $new_custom_fields, $this->options['custom_fields'] );
|
| 553 |
-
$diff2 = array_diff( $this->options['custom_fields'], $new_custom_fields );
|
| 554 |
-
$this->options['custom_fields'] = $new_custom_fields;
|
| 555 |
-
|
| 556 |
-
$this->save_options();
|
| 557 |
-
|
| 558 |
-
/*
|
| 559 |
-
If the list of custom fields was modified then we MUST resynchronize or
|
| 560 |
-
custom fields linked with existing posts may not be detected. This is somewhat
|
| 561 |
-
inefficient.
|
| 562 |
-
*/
|
| 563 |
-
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
| 564 |
-
$this->resynch();
|
| 565 |
-
}
|
| 566 |
-
}
|
| 567 |
-
|
| 568 |
-
}
|
| 569 |
-
|
| 570 |
-
?>
|
| 571 |
-
<div class="wrap"><h2>Broken Link Checker Options</h2>
|
| 572 |
-
|
| 573 |
-
<form name="link_checker_options" method="post" action="<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&updated=true">
|
| 574 |
-
|
| 575 |
-
<table class="form-table">
|
| 576 |
-
|
| 577 |
-
<tr valign="top">
|
| 578 |
-
<th scope="row">Status</th>
|
| 579 |
-
<td>
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
<div id='wsblc_full_status'>
|
| 583 |
-
<br/><br/><br/>
|
| 584 |
-
</div>
|
| 585 |
-
<script type='text/javascript'>
|
| 586 |
-
(function($){
|
| 587 |
-
|
| 588 |
-
function blcUpdateStatus(){
|
| 589 |
-
$.getJSON(
|
| 590 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 591 |
-
{
|
| 592 |
-
'action' : 'blc_full_status'
|
| 593 |
-
},
|
| 594 |
-
function (data, textStatus){
|
| 595 |
-
if ( data && ( typeof(data['text']) != 'undefined' ) ){
|
| 596 |
-
$('#wsblc_full_status').html(data.text);
|
| 597 |
-
} else {
|
| 598 |
-
$('#wsblc_full_status').html('[ Network error ]');
|
| 599 |
-
}
|
| 600 |
-
|
| 601 |
-
setTimeout(blcUpdateStatus, 10000); //...update every 10 seconds
|
| 602 |
-
}
|
| 603 |
-
);
|
| 604 |
-
}
|
| 605 |
-
blcUpdateStatus();//Call it the first time
|
| 606 |
-
|
| 607 |
-
})(jQuery);
|
| 608 |
-
</script>
|
| 609 |
-
<?php //JHS: Recheck all posts link: ?>
|
| 610 |
-
<p><input class="button" type="button" name="recheckbutton" value="Re-check all pages" onclick="location.replace('<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&recheck=true')" /></p>
|
| 611 |
-
</td>
|
| 612 |
-
</tr>
|
| 613 |
-
|
| 614 |
-
<tr valign="top">
|
| 615 |
-
<th scope="row">Check each link</th>
|
| 616 |
-
<td>
|
| 617 |
-
|
| 618 |
-
Every <input type="text" name="check_threshold" id="check_threshold"
|
| 619 |
-
value="<?php echo $this->options['check_threshold']; ?>" size='5' maxlength='3'/>
|
| 620 |
-
hours
|
| 621 |
-
<br/>
|
| 622 |
-
<span class="description">
|
| 623 |
-
Existing links will be checked this often. New links will usually be checked ASAP.
|
| 624 |
-
</span>
|
| 625 |
-
|
| 626 |
-
</td>
|
| 627 |
-
</tr>
|
| 628 |
-
|
| 629 |
-
<tr valign="top">
|
| 630 |
-
<th scope="row">Broken link CSS</th>
|
| 631 |
-
<td>
|
| 632 |
-
<input type="checkbox" name="mark_broken_links" id="mark_broken_links"
|
| 633 |
-
<?php if ($this->options['mark_broken_links']) echo ' checked="checked"'; ?>/>
|
| 634 |
-
<label for='mark_broken_links'>Apply <em>class="broken_link"</em> to broken links</label><br/>
|
| 635 |
-
<textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'/><?php
|
| 636 |
-
if( isset($this->options['broken_link_css']) )
|
| 637 |
-
echo $this->options['broken_link_css'];
|
| 638 |
-
?></textarea>
|
| 639 |
-
|
| 640 |
-
</td>
|
| 641 |
-
</tr>
|
| 642 |
-
|
| 643 |
-
<tr valign="top">
|
| 644 |
-
<th scope="row">Exclusion list</th>
|
| 645 |
-
<td>Don't check links where the URL contains any of these words (one per line) :<br/>
|
| 646 |
-
<textarea name="exclusion_list" id="exclusion_list" cols='45' rows='4' wrap='off'/><?php
|
| 647 |
-
if( isset($this->options['exclusion_list']) )
|
| 648 |
-
echo implode("\n", $this->options['exclusion_list']);
|
| 649 |
-
?></textarea>
|
| 650 |
-
|
| 651 |
-
</td>
|
| 652 |
-
</tr>
|
| 653 |
-
|
| 654 |
-
<tr valign="top">
|
| 655 |
-
<th scope="row">Custom fields</th>
|
| 656 |
-
<td>Check URLs entered in these custom fields (one per line) : <br/>
|
| 657 |
-
<textarea name="blc_custom_fields" id="blc_custom_fields" cols='45' rows='4' /><?php
|
| 658 |
-
if( isset($this->options['custom_fields']) )
|
| 659 |
-
echo implode("\n", $this->options['custom_fields']);
|
| 660 |
-
?></textarea>
|
| 661 |
-
|
| 662 |
-
</td>
|
| 663 |
-
</tr>
|
| 664 |
-
|
| 665 |
-
<tr valign="top">
|
| 666 |
-
<th scope="row">Max. execution time (advanced)</th>
|
| 667 |
-
<td>
|
| 668 |
-
|
| 669 |
-
<input type="text" name="max_execution_time" id="max_execution_time"
|
| 670 |
-
value="<?php echo $this->options['max_execution_time']; ?>" size='5' maxlength='3'/>
|
| 671 |
-
seconds
|
| 672 |
-
<br/><span class="description">
|
| 673 |
-
The plugin works by periodically creating a background worker instance that parses your posts looking for links,
|
| 674 |
-
checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most,
|
| 675 |
-
the background instance may run each time before stopping.
|
| 676 |
-
</span>
|
| 677 |
-
|
| 678 |
-
</td>
|
| 679 |
-
</tr>
|
| 680 |
-
|
| 681 |
-
</table>
|
| 682 |
-
|
| 683 |
-
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
| 684 |
-
</form>
|
| 685 |
-
</div>
|
| 686 |
-
<?php
|
| 687 |
-
}
|
| 688 |
-
|
| 689 |
-
function links_page(){
|
| 690 |
-
global $wpdb;
|
| 691 |
-
|
| 692 |
-
//Available filters by link type + the appropriate WHERE expressions
|
| 693 |
-
$filters = array(
|
| 694 |
-
'broken' => array(
|
| 695 |
-
'where_expr' => '( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( check_count > 0 ) AND ( http_code <> ' . BLC_CHECKING . ')',
|
| 696 |
-
'name' => 'Broken',
|
| 697 |
-
'heading' => 'Broken Links',
|
| 698 |
-
'heading_zero' => 'No broken links found'
|
| 699 |
-
),
|
| 700 |
-
'redirects' => array(
|
| 701 |
-
'where_expr' => '( redirect_count > 0 )',
|
| 702 |
-
'name' => 'Redirects',
|
| 703 |
-
'heading' => 'Redirected Links',
|
| 704 |
-
'heading_zero' => 'No redirects found'
|
| 705 |
-
),
|
| 706 |
-
|
| 707 |
-
'all' => array(
|
| 708 |
-
'where_expr' => '1',
|
| 709 |
-
'name' => 'All',
|
| 710 |
-
'heading' => 'Detected Links',
|
| 711 |
-
'heading_zero' => 'No links found (yet)'
|
| 712 |
-
),
|
| 713 |
-
);
|
| 714 |
-
|
| 715 |
-
$link_type = isset($_GET['link_type'])?$_GET['link_type']:'broken';
|
| 716 |
-
if ( !isset($filters[$link_type]) ){
|
| 717 |
-
$link_type = 'broken';
|
| 718 |
-
}
|
| 719 |
-
|
| 720 |
-
//Get the desired page number (must be > 0)
|
| 721 |
-
$page = isset($_GET['paged'])?intval($_GET['paged']):'1';
|
| 722 |
-
if ($page < 1) $page = 1;
|
| 723 |
-
|
| 724 |
-
//Links per page [1 - 200]
|
| 725 |
-
$per_page = isset($_GET['per_page'])?intval($_GET['per_page']):'30';
|
| 726 |
-
if ($per_page < 1){
|
| 727 |
-
$per_page = 30;
|
| 728 |
-
} else if ($per_page > 200){
|
| 729 |
-
$per_page = 200;
|
| 730 |
-
}
|
| 731 |
-
|
| 732 |
-
//calculate the number of various links
|
| 733 |
-
foreach ($filters as $filter => $data){
|
| 734 |
-
$filters[$filter]['count'] = $wpdb->get_var(
|
| 735 |
-
"SELECT COUNT(*) FROM {$wpdb->prefix}blc_links WHERE ".$data['where_expr'] );
|
| 736 |
-
}
|
| 737 |
-
$current_filter = $filters[$link_type];
|
| 738 |
-
$max_pages = ceil($current_filter['count'] / $per_page);
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
//Select the required links + 1 instance per link.
|
| 742 |
-
//Note : The query might be somewhat inefficient, but I can't think of any better way to do this.
|
| 743 |
-
$q = "SELECT
|
| 744 |
-
links.*,
|
| 745 |
-
instances.instance_id, instances.source_id, instances.source_type,
|
| 746 |
-
instances.link_text, instances.instance_type,
|
| 747 |
-
COUNT(*) as instance_count,
|
| 748 |
-
posts.post_title,
|
| 749 |
-
posts.post_date
|
| 750 |
-
|
| 751 |
-
FROM
|
| 752 |
-
{$wpdb->prefix}blc_links AS links,
|
| 753 |
-
{$wpdb->prefix}blc_instances as instances LEFT JOIN {$wpdb->posts} as posts ON instances.source_id = posts.ID
|
| 754 |
-
|
| 755 |
-
WHERE
|
| 756 |
-
links.link_id = instances.link_id
|
| 757 |
-
AND ". $current_filter['where_expr'] ."
|
| 758 |
-
|
| 759 |
-
GROUP BY links.link_id
|
| 760 |
-
LIMIT ".( ($page-1) * $per_page ).", $per_page";
|
| 761 |
-
//echo "<pre>$q</pre>";
|
| 762 |
-
|
| 763 |
-
$links = $wpdb->get_results($q, ARRAY_A);
|
| 764 |
-
if ($links){
|
| 765 |
-
/*
|
| 766 |
-
echo '<pre>';
|
| 767 |
-
print_r($links);
|
| 768 |
-
echo '</pre>';
|
| 769 |
-
//*/
|
| 770 |
-
} else {
|
| 771 |
-
echo $wpdb->last_error;
|
| 772 |
-
}
|
| 773 |
-
?>
|
| 774 |
-
|
| 775 |
-
<script type='text/javascript'>
|
| 776 |
-
var blc_current_filter = '<?php echo $link_type; ?>';
|
| 777 |
-
</script>
|
| 778 |
-
|
| 779 |
-
<style type='text/css'>
|
| 780 |
-
.blc-link-editor {
|
| 781 |
-
font-size: 1em;
|
| 782 |
-
width: 95%;
|
| 783 |
-
}
|
| 784 |
-
|
| 785 |
-
.blc-excluded-link {
|
| 786 |
-
background-color: #E2E2E2;
|
| 787 |
-
}
|
| 788 |
-
|
| 789 |
-
.blc-small-image {
|
| 790 |
-
display : block;
|
| 791 |
-
float: left;
|
| 792 |
-
padding-top: 2px;
|
| 793 |
-
margin-right: 3px;
|
| 794 |
-
}
|
| 795 |
-
</style>
|
| 796 |
-
|
| 797 |
-
<div class="wrap">
|
| 798 |
-
<h2><?php
|
| 799 |
-
//Output a header matching the current filter
|
| 800 |
-
if ( $current_filter['count'] > 0 ){
|
| 801 |
-
echo "<span class='current-link-count'>{$current_filter[count]}</span> " . $current_filter['heading'];
|
| 802 |
-
} else {
|
| 803 |
-
echo "<span class='current-link-count'></span>" . $current_filter['heading_zero'];
|
| 804 |
-
}
|
| 805 |
-
?></h2>
|
| 806 |
-
|
| 807 |
-
<div class='tablenav'>
|
| 808 |
-
<ul class="subsubsub">
|
| 809 |
-
<?php
|
| 810 |
-
//Construct a submenu of filter types
|
| 811 |
-
$items = array();
|
| 812 |
-
foreach ($filters as $filter => $data){
|
| 813 |
-
$class = $number_class = '';
|
| 814 |
-
|
| 815 |
-
if ( $link_type == $filter ) $class = 'class="current"';
|
| 816 |
-
if ( $link_type == $filter ) $number_class = 'current-link-count';
|
| 817 |
-
|
| 818 |
-
$items[] = "<li><a href='tools.php?page=view-broken-links&link_type=$filter' $class>
|
| 819 |
-
{$data[name]}</a> <span class='count'>(<span class='$number_class'>{$data[count]}</span>)</span>";
|
| 820 |
-
}
|
| 821 |
-
echo implode(' |</li>', $items);
|
| 822 |
-
unset($items);
|
| 823 |
-
?>
|
| 824 |
-
</ul>
|
| 825 |
-
<?php
|
| 826 |
-
//Display pagination links
|
| 827 |
-
$page_links = paginate_links( array(
|
| 828 |
-
'base' => add_query_arg( 'paged', '%#%' ),
|
| 829 |
-
'format' => '',
|
| 830 |
-
'prev_text' => __('«'),
|
| 831 |
-
'next_text' => __('»'),
|
| 832 |
-
'total' => $max_pages,
|
| 833 |
-
'current' => $page
|
| 834 |
-
));
|
| 835 |
-
|
| 836 |
-
if ( $page_links ) {
|
| 837 |
-
echo '<div class="tablenav-pages">';
|
| 838 |
-
$page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>' ) . '</span>%s',
|
| 839 |
-
number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
|
| 840 |
-
number_format_i18n( min( $page * $per_page, count($links) ) ),
|
| 841 |
-
number_format_i18n( $current_filter['count'] ),
|
| 842 |
-
$page_links
|
| 843 |
-
);
|
| 844 |
-
echo $page_links_text;
|
| 845 |
-
echo '</div>';
|
| 846 |
-
}
|
| 847 |
-
?>
|
| 848 |
-
|
| 849 |
-
</div>
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
<?php
|
| 854 |
-
if($links && (count($links)>0)){
|
| 855 |
-
?>
|
| 856 |
-
<table class="widefat">
|
| 857 |
-
<thead>
|
| 858 |
-
<tr>
|
| 859 |
-
|
| 860 |
-
<th scope="col">Source
|
| 861 |
-
</th>
|
| 862 |
-
<th scope="col">Link Text</th>
|
| 863 |
-
<th scope="col">URL</th>
|
| 864 |
-
|
| 865 |
-
<?php if ( 'broken' == $link_type ) { ?>
|
| 866 |
-
<th scope="col"> </th>
|
| 867 |
-
<?php } ?>
|
| 868 |
-
|
| 869 |
-
</tr>
|
| 870 |
-
</thead>
|
| 871 |
-
<tbody id="the-list">
|
| 872 |
-
<?php
|
| 873 |
-
$rowclass = ''; $rownum = 0;
|
| 874 |
-
foreach ($links as $link) {
|
| 875 |
-
$rownum++;
|
| 876 |
-
|
| 877 |
-
$rowclass = 'alternate' == $rowclass ? '' : 'alternate';
|
| 878 |
-
$excluded = $this->is_excluded( $link['url'] );
|
| 879 |
-
if ( $excluded ) $rowclass .= ' blc-excluded-link';
|
| 880 |
-
|
| 881 |
-
?>
|
| 882 |
-
<tr id='<?php echo "blc-row-$rownum"; ?>' class='blc-row <?php echo $rowclass; ?>'>
|
| 883 |
-
<td class='post-title column-title'>
|
| 884 |
-
<span class='blc-link-id' style='display:none;'><?php echo $link['link_id']; ?></span>
|
| 885 |
-
<?php
|
| 886 |
-
if ( ('post' == $link['source_type']) || ('custom_field' == $link['source_type']) ){
|
| 887 |
-
|
| 888 |
-
echo "<a class='row-title' href='post.php?action=edit&post=$link[source_id]' title='Edit this post'>{$link[post_title]}</a>";
|
| 889 |
-
|
| 890 |
-
//Output inline action links (copied from edit-post-rows.php)
|
| 891 |
-
$actions = array();
|
| 892 |
-
if ( current_user_can('edit_post', $link['source_id']) ) {
|
| 893 |
-
$actions['edit'] = '<span class="edit"><a href="' . get_edit_post_link($link['source_id'], true) . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>';
|
| 894 |
-
$actions['delete'] = "<span class='delete'><a class='submitdelete' title='" . attribute_escape(__('Delete this post')) . "' href='" . wp_nonce_url("post.php?action=delete&post=".$link['source_id'], 'delete-post_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete the post '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['post_title'] )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
| 895 |
-
}
|
| 896 |
-
$actions['view'] = '<span class="view"><a href="' . get_permalink($link['source_id']) . '" title="' . attribute_escape(sprintf(__('View "%s"'), $link['post_title'])) . '" rel="permalink">' . __('View') . '</a>';
|
| 897 |
-
echo '<div class="row-actions">';
|
| 898 |
-
echo implode(' | </span>', $actions);
|
| 899 |
-
echo '</div>';
|
| 900 |
-
|
| 901 |
-
} elseif ( 'blogroll' == $link['source_type'] ) {
|
| 902 |
-
|
| 903 |
-
echo "<a class='row-title' href='link.php?action=edit&link_id=$link[source_id]' title='Edit this bookmark'>{$link[link_text]}</a>";
|
| 904 |
-
|
| 905 |
-
//Output inline action links
|
| 906 |
-
$actions = array();
|
| 907 |
-
if ( current_user_can('manage_links') ) {
|
| 908 |
-
$actions['edit'] = '<span class="edit"><a href="link.php?action=edit&link_id=' . $link['source_id'] . '" title="' . attribute_escape(__('Edit this bookmark')) . '">' . __('Edit') . '</a>';
|
| 909 |
-
$actions['delete'] = "<span class='delete'><a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&link_id={$link[source_id]}", 'delete-bookmark_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['link_text'])) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
| 910 |
-
}
|
| 911 |
-
|
| 912 |
-
echo '<div class="row-actions">';
|
| 913 |
-
echo implode(' | </span>', $actions);
|
| 914 |
-
echo '</div>';
|
| 915 |
-
|
| 916 |
-
} elseif ( empty($link['source_type']) ){
|
| 917 |
-
|
| 918 |
-
echo "[An orphaned link! This is a bug.]";
|
| 919 |
-
|
| 920 |
-
}
|
| 921 |
-
?>
|
| 922 |
-
</td>
|
| 923 |
-
<td class='blc-link-text'><?php
|
| 924 |
-
if ( 'post' == $link['source_type'] ){
|
| 925 |
-
|
| 926 |
-
if ( 'link' == $link['instance_type'] ) {
|
| 927 |
-
print strip_tags($link['link_text']);
|
| 928 |
-
} elseif ( 'image' == $link['instance_type'] ){
|
| 929 |
-
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/image.png' class='blc-small-image' alt='Image' title='Image'> Image";
|
| 930 |
-
} else {
|
| 931 |
-
echo '[ ??? ]';
|
| 932 |
-
}
|
| 933 |
-
|
| 934 |
-
} elseif ( 'custom_field' == $link['source_type'] ){
|
| 935 |
-
|
| 936 |
-
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/script_code.png' class='blc-small-image' title='Custom field' alt='Custom field'> ";
|
| 937 |
-
echo "<code>".$link['link_text']."</code>";
|
| 938 |
-
|
| 939 |
-
} elseif ( 'blogroll' == $link['source_type'] ){
|
| 940 |
-
//echo $link['link_text'];
|
| 941 |
-
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/link.png' class='blc-small-image' title='Bookmark' alt='Bookmark'> Bookmark";
|
| 942 |
-
}
|
| 943 |
-
?>
|
| 944 |
-
</td>
|
| 945 |
-
<td class='column-url'>
|
| 946 |
-
<a href='<?php print $link['url']; ?>' target='_blank' class='blc-link-url'>
|
| 947 |
-
<?php print $this->mytruncate($link['url']); ?></a>
|
| 948 |
-
<input type='text' id='link-editor-<?php print $rownum; ?>'
|
| 949 |
-
value='<?php print attribute_escape($link['url']); ?>'
|
| 950 |
-
class='blc-link-editor' style='display:none' />
|
| 951 |
-
<?php
|
| 952 |
-
//Output inline action links for the link/URL
|
| 953 |
-
$actions = array();
|
| 954 |
-
|
| 955 |
-
$actions['details'] = "<span class='view'><a class='blc-details-button' href='javascript:void(0)' title='Show more info about this link'>Details</a>";
|
| 956 |
-
|
| 957 |
-
$actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='Remove this link from all posts' ".
|
| 958 |
-
"id='unlink-button-$rownum' href='javascript:void(0);'>Unlink</a>";
|
| 959 |
-
|
| 960 |
-
if ( $excluded ){
|
| 961 |
-
$actions['exclude'] = "<span class='delete'>Excluded";
|
| 962 |
-
} else {
|
| 963 |
-
$actions['exclude'] = "<span class='delete'><a class='submitdelete blc-exclude-button' title='Add this URL to the exclusion list' ".
|
| 964 |
-
"id='exclude-button-$rownum' href='javascript:void(0);'>Exclude</a>";
|
| 965 |
-
}
|
| 966 |
-
|
| 967 |
-
$actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='Edit link URL'>Edit URL</a>";
|
| 968 |
-
|
| 969 |
-
echo '<div class="row-actions">';
|
| 970 |
-
echo implode(' | </span>', $actions);
|
| 971 |
-
|
| 972 |
-
echo "<span style='display:none' class='blc-cancel-button-container'> ",
|
| 973 |
-
"| <a href='javascript:void(0)' class='blc-cancel-button' title='Cancel URL editing'>Cancel</a></span>";
|
| 974 |
-
|
| 975 |
-
echo '</div>';
|
| 976 |
-
?>
|
| 977 |
-
</td>
|
| 978 |
-
<?php if ( 'broken' == $link_type ) { ?>
|
| 979 |
-
<td><a href='javascript:void(0);'
|
| 980 |
-
id='discard_button-<?php print $rownum; ?>'
|
| 981 |
-
class='blc-discard-button'
|
| 982 |
-
title='Remove this message and mark the link as valid'>Discard</a>
|
| 983 |
-
</td>
|
| 984 |
-
<?php } ?>
|
| 985 |
-
</tr>
|
| 986 |
-
<!-- Link details -->
|
| 987 |
-
<tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'>
|
| 988 |
-
<td colspan='4'><?php $this->link_details_row($link); ?></td>
|
| 989 |
-
</tr><?php
|
| 990 |
-
}
|
| 991 |
-
?></tbody></table><?php
|
| 992 |
-
|
| 993 |
-
//Also display pagination links at the bottom
|
| 994 |
-
if ( $page_links ) {
|
| 995 |
-
echo '<div class="tablenav"><div class="tablenav-pages">';
|
| 996 |
-
$page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>' ) . '</span>%s',
|
| 997 |
-
number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
|
| 998 |
-
number_format_i18n( min( $page * $per_page, count($links) ) ),
|
| 999 |
-
number_format_i18n( $current_filter['count'] ),
|
| 1000 |
-
$page_links
|
| 1001 |
-
);
|
| 1002 |
-
echo $page_links_text;
|
| 1003 |
-
echo '</div></div>';
|
| 1004 |
-
}
|
| 1005 |
-
};
|
| 1006 |
-
?>
|
| 1007 |
-
<?php $this->links_page_js(); ?>
|
| 1008 |
-
</div>
|
| 1009 |
-
<?php
|
| 1010 |
-
}
|
| 1011 |
-
|
| 1012 |
-
function links_page_js(){
|
| 1013 |
-
?>
|
| 1014 |
-
<script type='text/javascript'>
|
| 1015 |
|
| 1016 |
-
|
| 1017 |
-
|
| 1018 |
-
|
| 1019 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1020 |
}
|
| 1021 |
|
| 1022 |
-
jQuery(function($){
|
| 1023 |
-
|
| 1024 |
-
//The discard button - manually mark the link as valid. The link will be checked again later.
|
| 1025 |
-
$(".blc-discard-button").click(function () {
|
| 1026 |
-
var me = this;
|
| 1027 |
-
$(me).html('Wait...');
|
| 1028 |
-
|
| 1029 |
-
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 1030 |
-
|
| 1031 |
-
$.post(
|
| 1032 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1033 |
-
{
|
| 1034 |
-
'action' : 'blc_discard',
|
| 1035 |
-
'link_id' : link_id
|
| 1036 |
-
},
|
| 1037 |
-
function (data, textStatus){
|
| 1038 |
-
if (data == 'OK'){
|
| 1039 |
-
var master = $(me).parents('.blc-row');
|
| 1040 |
-
var details = master.next('.blc-link-details');
|
| 1041 |
-
|
| 1042 |
-
details.hide();
|
| 1043 |
-
//Flash the main row green to indicate success, then hide it.
|
| 1044 |
-
var oldColor = master.css('background-color');
|
| 1045 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
| 1046 |
-
master.hide();
|
| 1047 |
-
});
|
| 1048 |
-
|
| 1049 |
-
alterLinkCounter(-1);
|
| 1050 |
-
} else {
|
| 1051 |
-
$(me).html('Discard');
|
| 1052 |
-
alert(data);
|
| 1053 |
-
}
|
| 1054 |
-
}
|
| 1055 |
-
);
|
| 1056 |
-
});
|
| 1057 |
-
|
| 1058 |
-
//The details button - display/hide detailed info about a link
|
| 1059 |
-
$(".blc-details-button, .blc-link-text").click(function () {
|
| 1060 |
-
$(this).parents('.blc-row').next('.blc-link-details').toggle();
|
| 1061 |
-
});
|
| 1062 |
-
|
| 1063 |
-
//The edit button - edit/save the link's URL
|
| 1064 |
-
$(".blc-edit-button").click(function () {
|
| 1065 |
-
var edit_button = $(this);
|
| 1066 |
-
var master = $(edit_button).parents('.blc-row');
|
| 1067 |
-
var editor = $(master).find('.blc-link-editor');
|
| 1068 |
-
var url_el = $(master).find('.blc-link-url');
|
| 1069 |
-
var cancel_button_container = $(master).find('.blc-cancel-button-container');
|
| 1070 |
-
|
| 1071 |
-
//Find the current/original URL
|
| 1072 |
-
var orig_url = url_el.attr('href');
|
| 1073 |
-
//Find the link ID
|
| 1074 |
-
var link_id = $(master).find('.blc-link-id').html();
|
| 1075 |
-
|
| 1076 |
-
if ( !$(editor).is(':visible') ){
|
| 1077 |
-
//Begin editing
|
| 1078 |
-
url_el.hide();
|
| 1079 |
-
editor.show();
|
| 1080 |
-
cancel_button_container.show();
|
| 1081 |
-
editor.focus();
|
| 1082 |
-
editor.select();
|
| 1083 |
-
edit_button.html('Save URL');
|
| 1084 |
-
} else {
|
| 1085 |
-
editor.hide();
|
| 1086 |
-
cancel_button_container.hide();
|
| 1087 |
-
url_el.show();
|
| 1088 |
-
|
| 1089 |
-
new_url = editor.val();
|
| 1090 |
-
|
| 1091 |
-
if (new_url != orig_url){
|
| 1092 |
-
//Save the changed link
|
| 1093 |
-
url_el.html('Saving changes...');
|
| 1094 |
-
|
| 1095 |
-
$.getJSON(
|
| 1096 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1097 |
-
{
|
| 1098 |
-
'action' : 'blc_edit',
|
| 1099 |
-
'link_id' : link_id,
|
| 1100 |
-
'new_url' : new_url
|
| 1101 |
-
},
|
| 1102 |
-
function (data, textStatus){
|
| 1103 |
-
var display_url = '';
|
| 1104 |
-
|
| 1105 |
-
if ( data && (typeof(data['error']) != 'undefined') ){
|
| 1106 |
-
//data.error is an error message
|
| 1107 |
-
alert(data.error);
|
| 1108 |
-
display_url = orig_url;
|
| 1109 |
-
} else {
|
| 1110 |
-
//data contains info about the performed edit
|
| 1111 |
-
if ( data.cnt_okay > 0 ){
|
| 1112 |
-
display_url = new_url;
|
| 1113 |
-
|
| 1114 |
-
url_el.attr('href', new_url);
|
| 1115 |
-
|
| 1116 |
-
if ( data.cnt_error > 0 ){
|
| 1117 |
-
var msg = "The link was successfully modifed.";
|
| 1118 |
-
msg = msg + "\nHowever, "+data.cnt_error+" instances couldn't be edited and still point to the old URL."
|
| 1119 |
-
alert(msg);
|
| 1120 |
-
} else {
|
| 1121 |
-
//Flash the row green to indicate success
|
| 1122 |
-
var oldColor = master.css('background-color');
|
| 1123 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
|
| 1124 |
-
|
| 1125 |
-
//Save the new ID
|
| 1126 |
-
master.find('.blc-link-id').html(data.new_link_id);
|
| 1127 |
-
//Load up the new link info (so sue me)
|
| 1128 |
-
master.next('.blc-link-details').find('td').html('<center>Loading...</center>').load(
|
| 1129 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1130 |
-
{
|
| 1131 |
-
'action' : 'blc_link_details',
|
| 1132 |
-
'link_id' : data.new_link_id
|
| 1133 |
-
}
|
| 1134 |
-
);
|
| 1135 |
-
}
|
| 1136 |
-
} else {
|
| 1137 |
-
alert("Something went wrong. The plugin failed to edit "+
|
| 1138 |
-
data.cnt_error + ' instance(s) of this link.');
|
| 1139 |
-
|
| 1140 |
-
display_url = orig_url;
|
| 1141 |
-
}
|
| 1142 |
-
};
|
| 1143 |
-
|
| 1144 |
-
//Shorten the displayed URL if it's > 50 characters
|
| 1145 |
-
if ( display_url.length > 50 ){
|
| 1146 |
-
display_url = display_url.substr(0, 47) + '...';
|
| 1147 |
-
}
|
| 1148 |
-
url_el.html(display_url);
|
| 1149 |
-
}
|
| 1150 |
-
);
|
| 1151 |
-
|
| 1152 |
-
} else {
|
| 1153 |
-
//It's the same URL, so do nothing.
|
| 1154 |
-
}
|
| 1155 |
-
edit_button.html('Edit URL');
|
| 1156 |
-
}
|
| 1157 |
-
});
|
| 1158 |
-
|
| 1159 |
-
$(".blc-cancel-button").click(function () {
|
| 1160 |
-
var master = $(this).parents('.blc-row');
|
| 1161 |
-
var url_el = $(master).find('.blc-link-url');
|
| 1162 |
-
|
| 1163 |
-
//Hide the cancel button
|
| 1164 |
-
$(this).parent().hide();
|
| 1165 |
-
//Show the un-editable URL again
|
| 1166 |
-
url_el.show();
|
| 1167 |
-
//reset and hide the editor
|
| 1168 |
-
master.find('.blc-link-editor').hide().val(url_el.attr('href'));
|
| 1169 |
-
//Set the edit button to say "Edit URL"
|
| 1170 |
-
master.find('.blc-edit-button').html('Edit URL');
|
| 1171 |
-
});
|
| 1172 |
-
|
| 1173 |
-
//The unlink button - remove the link/image from all posts, custom fields, etc.
|
| 1174 |
-
$(".blc-unlink-button").click(function () {
|
| 1175 |
-
var me = this;
|
| 1176 |
-
var master = $(me).parents('.blc-row');
|
| 1177 |
-
$(me).html('Wait...');
|
| 1178 |
-
|
| 1179 |
-
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 1180 |
-
|
| 1181 |
-
$.post(
|
| 1182 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1183 |
-
{
|
| 1184 |
-
'action' : 'blc_unlink',
|
| 1185 |
-
'link_id' : link_id
|
| 1186 |
-
},
|
| 1187 |
-
function (data, textStatus){
|
| 1188 |
-
eval('data = ' + data);
|
| 1189 |
-
|
| 1190 |
-
if ( data && ( typeof(data['ok']) != 'undefined') ){
|
| 1191 |
-
//Hide the details
|
| 1192 |
-
master.next('.blc-link-details').hide();
|
| 1193 |
-
//Flash the main row green to indicate success, then hide it.
|
| 1194 |
-
var oldColor = master.css('background-color');
|
| 1195 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
| 1196 |
-
master.hide();
|
| 1197 |
-
});
|
| 1198 |
-
|
| 1199 |
-
alterLinkCounter(-1);
|
| 1200 |
-
} else {
|
| 1201 |
-
$(me).html('Unlink');
|
| 1202 |
-
//Show the error message
|
| 1203 |
-
alert(data.error);
|
| 1204 |
-
}
|
| 1205 |
-
}
|
| 1206 |
-
);
|
| 1207 |
-
});
|
| 1208 |
-
|
| 1209 |
-
//The exclude button - Add this link to the exclusion list
|
| 1210 |
-
$(".blc-exclude-button").click(function () {
|
| 1211 |
-
var me = this;
|
| 1212 |
-
var master = $(me).parents('.blc-row');
|
| 1213 |
-
var details = master.next('.blc-link-details');
|
| 1214 |
-
$(me).html('Wait...');
|
| 1215 |
-
|
| 1216 |
-
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 1217 |
-
|
| 1218 |
-
$.post(
|
| 1219 |
-
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1220 |
-
{
|
| 1221 |
-
'action' : 'blc_exclude_link',
|
| 1222 |
-
'link_id' : link_id
|
| 1223 |
-
},
|
| 1224 |
-
function (data, textStatus){
|
| 1225 |
-
eval('data = ' + data);
|
| 1226 |
-
|
| 1227 |
-
if ( data && ( typeof(data['ok']) != 'undefined' ) ){
|
| 1228 |
-
|
| 1229 |
-
if ( 'broken' == blc_current_filter ){
|
| 1230 |
-
//Flash the row green to indicate success, then hide it.
|
| 1231 |
-
$(me).replaceWith('Excluded');
|
| 1232 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 200, function(){
|
| 1233 |
-
details.hide();
|
| 1234 |
-
master.hide();
|
| 1235 |
-
alterLinkCounter(-1);
|
| 1236 |
-
});
|
| 1237 |
-
master.addClass('blc-excluded-link');
|
| 1238 |
-
} else {
|
| 1239 |
-
//Flash the row green to indicate success and fade to the "excluded link" color
|
| 1240 |
-
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 300);
|
| 1241 |
-
master.addClass('blc-excluded-link');
|
| 1242 |
-
$(me).replaceWith('Excluded');
|
| 1243 |
-
}
|
| 1244 |
-
} else {
|
| 1245 |
-
$(me).html('Exclude');
|
| 1246 |
-
alert(data.error);
|
| 1247 |
-
}
|
| 1248 |
-
}
|
| 1249 |
-
);
|
| 1250 |
-
});
|
| 1251 |
-
|
| 1252 |
-
});
|
| 1253 |
-
|
| 1254 |
-
</script>
|
| 1255 |
-
<?php
|
| 1256 |
-
}
|
| 1257 |
-
|
| 1258 |
-
function link_details_row($link){
|
| 1259 |
-
?>
|
| 1260 |
-
<span id='post_date_full' style='display:none;'><?php
|
| 1261 |
-
print $link['post_date'];
|
| 1262 |
-
?></span>
|
| 1263 |
-
<span id='check_date_full' style='display:none;'><?php
|
| 1264 |
-
print $link['last_check'];
|
| 1265 |
-
?></span>
|
| 1266 |
-
<ol style='list-style-type: none; width: 50%; float: right;'>
|
| 1267 |
-
<li><strong>Log :</strong>
|
| 1268 |
-
<span class='blc_log'><?php
|
| 1269 |
-
print nl2br($link['log']);
|
| 1270 |
-
?></span></li>
|
| 1271 |
-
</ol>
|
| 1272 |
-
|
| 1273 |
-
<ol style='list-style-type: none; padding-left: 2px;'>
|
| 1274 |
-
<?php if ( !empty($link['post_date']) ) { ?>
|
| 1275 |
-
<li><strong>Post published on :</strong>
|
| 1276 |
-
<span class='post_date'><?php
|
| 1277 |
-
print strftime("%B %d, %Y",strtotime($link['post_date']));
|
| 1278 |
-
?></span></li>
|
| 1279 |
-
<?php } ?>
|
| 1280 |
-
<li><strong>Link last checked :</strong>
|
| 1281 |
-
<span class='check_date'><?php
|
| 1282 |
-
$last_check = strtotime($link['last_check']);
|
| 1283 |
-
if ( $last_check < strtotime('-10 years') ){
|
| 1284 |
-
echo 'Never';
|
| 1285 |
-
} else {
|
| 1286 |
-
echo strftime( "%B %d, %Y", $last_check );
|
| 1287 |
-
}
|
| 1288 |
-
?></span></li>
|
| 1289 |
-
|
| 1290 |
-
<li><strong>HTTP code :</strong>
|
| 1291 |
-
<span class='http_code'><?php
|
| 1292 |
-
print $link['http_code'];
|
| 1293 |
-
?></span></li>
|
| 1294 |
-
|
| 1295 |
-
<li><strong>Response time :</strong>
|
| 1296 |
-
<span class='request_duration'><?php
|
| 1297 |
-
printf('%2.3f seconds', $link['request_duration']);
|
| 1298 |
-
?></span></li>
|
| 1299 |
-
|
| 1300 |
-
<li><strong>Final URL :</strong>
|
| 1301 |
-
<span class='final_url'><?php
|
| 1302 |
-
print $link['final_url'];
|
| 1303 |
-
?></span></li>
|
| 1304 |
-
|
| 1305 |
-
<li><strong>Redirect count :</strong>
|
| 1306 |
-
<span class='redirect_count'><?php
|
| 1307 |
-
print $link['redirect_count'];
|
| 1308 |
-
?></span></li>
|
| 1309 |
-
|
| 1310 |
-
<li><strong>Instance count :</strong>
|
| 1311 |
-
<span class='instance_count'><?php
|
| 1312 |
-
print $link['instance_count'];
|
| 1313 |
-
?></span></li>
|
| 1314 |
-
|
| 1315 |
-
<?php if ( intval( $link['check_count'] ) > 0 ){ ?>
|
| 1316 |
-
<li><br/>This link has failed
|
| 1317 |
-
<span class='check_count'><?php
|
| 1318 |
-
echo $link['check_count'];
|
| 1319 |
-
if ( intval($link['check_count'])==1 ){
|
| 1320 |
-
echo ' time';
|
| 1321 |
-
} else {
|
| 1322 |
-
echo ' times';
|
| 1323 |
-
}
|
| 1324 |
-
?></span>.</li>
|
| 1325 |
-
<?php } ?>
|
| 1326 |
-
</ol>
|
| 1327 |
-
<?php
|
| 1328 |
-
}
|
| 1329 |
-
|
| 1330 |
-
/**
|
| 1331 |
-
* ws_broken_link_checker::cleanup_links()
|
| 1332 |
-
* Remove orphaned links that have no corresponding instances
|
| 1333 |
-
*
|
| 1334 |
-
* @param int $link_id (optional) Only check this link
|
| 1335 |
-
* @return bool
|
| 1336 |
-
*/
|
| 1337 |
-
function cleanup_links( $link_id = null ){
|
| 1338 |
-
global $wpdb;
|
| 1339 |
-
|
| 1340 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_links
|
| 1341 |
-
USING {$wpdb->prefix}blc_links LEFT JOIN {$wpdb->prefix}blc_instances
|
| 1342 |
-
ON {$wpdb->prefix}blc_instances.link_id = {$wpdb->prefix}blc_links.link_id
|
| 1343 |
-
WHERE
|
| 1344 |
-
{$wpdb->prefix}blc_instances.link_id IS NULL";
|
| 1345 |
-
|
| 1346 |
-
if ( $link_id !==null ) {
|
| 1347 |
-
$q .= " AND {$wpdb->prefix}blc_links.link_id = " . intval( $link_id );
|
| 1348 |
-
}
|
| 1349 |
-
|
| 1350 |
-
return $wpdb->query( $q );
|
| 1351 |
-
}
|
| 1352 |
-
|
| 1353 |
-
/**
|
| 1354 |
-
* ws_broken_link_checker::cleanup_instances()
|
| 1355 |
-
* Remove instances that reference invalid posts or bookmarks
|
| 1356 |
-
*
|
| 1357 |
-
* @return bool
|
| 1358 |
-
*/
|
| 1359 |
-
function cleanup_instances(){
|
| 1360 |
-
global $wpdb;
|
| 1361 |
-
|
| 1362 |
-
//Delete all instances that reference non-existent posts
|
| 1363 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1364 |
-
USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->posts} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->posts}.ID
|
| 1365 |
-
WHERE
|
| 1366 |
-
{$wpdb->posts}.ID IS NULL
|
| 1367 |
-
AND ( ( {$wpdb->prefix}blc_instances.source_type = 'post' ) OR ( {$wpdb->prefix}blc_instances.source_type = 'custom_field' ) )";
|
| 1368 |
-
$rez = $wpdb->query($q);
|
| 1369 |
-
|
| 1370 |
-
//Delete all instances that reference non-existant bookmarks
|
| 1371 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1372 |
-
USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->links} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->links}.link_id
|
| 1373 |
-
WHERE
|
| 1374 |
-
{$wpdb->links}.link_id IS NULL
|
| 1375 |
-
AND {$wpdb->prefix}blc_instances.source_type = 'blogroll' ";
|
| 1376 |
-
$rez2 = $wpdb->query($q);
|
| 1377 |
-
|
| 1378 |
-
return $rez and $rez2;
|
| 1379 |
-
}
|
| 1380 |
-
|
| 1381 |
-
function load_options(){
|
| 1382 |
-
$this->options = get_option($this->options_name);
|
| 1383 |
-
if( !is_array( $this->options ) ){
|
| 1384 |
-
$this->options = $this->defaults;
|
| 1385 |
-
} else {
|
| 1386 |
-
$this->options = array_merge( $this->defaults, $this->options );
|
| 1387 |
-
}
|
| 1388 |
-
}
|
| 1389 |
-
|
| 1390 |
-
function save_options(){
|
| 1391 |
-
update_option($this->options_name,$this->options);
|
| 1392 |
-
}
|
| 1393 |
-
|
| 1394 |
-
/**
|
| 1395 |
-
* ws_broken_link_checker::parse_post()
|
| 1396 |
-
* Parse a post for links and save them to the DB.
|
| 1397 |
-
*
|
| 1398 |
-
* @param string $content Post content
|
| 1399 |
-
* @param int $post_id Post ID
|
| 1400 |
-
* @return void
|
| 1401 |
-
*/
|
| 1402 |
-
function parse_post($content, $post_id){
|
| 1403 |
-
//remove all <code></code> blocks first
|
| 1404 |
-
$content = preg_replace('/<code>.+?<\/code>/i', ' ', $content);
|
| 1405 |
-
//remove all <pre></pre> blocks as well
|
| 1406 |
-
$content = preg_replace('/<pre[^>]*>.+?<\/pre>/i', ' ', $content);
|
| 1407 |
-
//Get the post permalink - it's used to resolve relative URLs
|
| 1408 |
-
$permalink = get_permalink( $post_id );
|
| 1409 |
-
|
| 1410 |
-
//Find links
|
| 1411 |
-
if(preg_match_all(blcUtility::link_pattern(), $content, $matches, PREG_SET_ORDER)){
|
| 1412 |
-
foreach($matches as $link){
|
| 1413 |
-
$url = $link[3];
|
| 1414 |
-
$text = strip_tags( $link[5] );
|
| 1415 |
-
//FB::log($url, "Found link");
|
| 1416 |
-
|
| 1417 |
-
$url = blcUtility::normalize_url($url, $permalink);
|
| 1418 |
-
//Skip invalid links
|
| 1419 |
-
if ( !$url || (strlen($url)<6) ) continue;
|
| 1420 |
-
|
| 1421 |
-
//Create or load the link
|
| 1422 |
-
$link_obj = new blcLink($url);
|
| 1423 |
-
//Add & save a new instance
|
| 1424 |
-
$link_obj->add_instance($post_id, 'post', $text, 'link');
|
| 1425 |
-
}
|
| 1426 |
-
};
|
| 1427 |
-
|
| 1428 |
-
//Find images (<img src=...>)
|
| 1429 |
-
if(preg_match_all(blcUtility::img_pattern(), $content, $matches, PREG_SET_ORDER)){
|
| 1430 |
-
foreach($matches as $img){
|
| 1431 |
-
$url = $img[3];
|
| 1432 |
-
//FB::log($url, "Found image");
|
| 1433 |
-
|
| 1434 |
-
$url = blcUtility::normalize_url($url, $permalink);
|
| 1435 |
-
if ( !$url || (strlen($url)<6) ) continue; //skip invalid URLs
|
| 1436 |
-
|
| 1437 |
-
//Create or load the link
|
| 1438 |
-
$link = new blcLink($url);
|
| 1439 |
-
//Add & save a new image instance
|
| 1440 |
-
$link->add_instance($post_id, 'post', '', 'image');
|
| 1441 |
-
}
|
| 1442 |
-
};
|
| 1443 |
-
}
|
| 1444 |
-
|
| 1445 |
-
/**
|
| 1446 |
-
* ws_broken_link_checker::parse_post_meta()
|
| 1447 |
-
* Parse a post's custom fields for links and save them in the DB.
|
| 1448 |
-
*
|
| 1449 |
-
* @param id $post_id
|
| 1450 |
-
* @return void
|
| 1451 |
-
*/
|
| 1452 |
-
function parse_post_meta($post_id){
|
| 1453 |
-
//Get all custom fields of this post
|
| 1454 |
-
$custom_fields = get_post_custom( $post_id );
|
| 1455 |
-
//FB::log($custom_fields, "Custom fields loaded");
|
| 1456 |
-
|
| 1457 |
-
//Parse the enabled fields
|
| 1458 |
-
foreach( $this->options['custom_fields'] as $field ){
|
| 1459 |
-
if ( !isset($custom_fields[$field]) ) continue;
|
| 1460 |
-
|
| 1461 |
-
//FB::log($field, "Parsing field");
|
| 1462 |
-
|
| 1463 |
-
$values = $custom_fields[$field];
|
| 1464 |
-
if ( !is_array( $values ) ) $values = array($values);
|
| 1465 |
-
|
| 1466 |
-
foreach( $values as $value ){
|
| 1467 |
-
|
| 1468 |
-
//Attempt to parse the $value as URL
|
| 1469 |
-
$url = blcUtility::normalize_url($value);
|
| 1470 |
-
if ( empty($url) ){
|
| 1471 |
-
//FB::warn($value, "Invalid URL in custom field ".$field);
|
| 1472 |
-
continue;
|
| 1473 |
-
}
|
| 1474 |
-
|
| 1475 |
-
//FB::log($url, "Found URL");
|
| 1476 |
-
$link = new blcLink( $url );
|
| 1477 |
-
//FB::log($link, 'Created/loaded link');
|
| 1478 |
-
$inst = $link->add_instance( $post_id, 'custom_field', $field, 'link' );
|
| 1479 |
-
//FB::log($inst, 'Created instance');
|
| 1480 |
-
}
|
| 1481 |
-
}
|
| 1482 |
-
|
| 1483 |
-
}
|
| 1484 |
-
|
| 1485 |
-
function parse_blogroll_link( $the_link ){
|
| 1486 |
-
//FB::log($the_link, "Parsing blogroll link");
|
| 1487 |
-
|
| 1488 |
-
//Attempt to parse the URL
|
| 1489 |
-
$url = blcUtility::normalize_url( $the_link['link_url'] );
|
| 1490 |
-
if ( empty($url) ){
|
| 1491 |
-
//FB::warn( $the_link['link_url'], "Invalid URL in for a blogroll link".$the_link['link_name'] );
|
| 1492 |
-
return false;
|
| 1493 |
-
}
|
| 1494 |
-
|
| 1495 |
-
//FB::log($url, "Found URL");
|
| 1496 |
-
$link = new blcLink( $url );
|
| 1497 |
-
return $link->add_instance( $the_link['link_id'], 'blogroll', $the_link['link_name'], 'link' );
|
| 1498 |
-
}
|
| 1499 |
-
|
| 1500 |
-
function start_timer(){
|
| 1501 |
-
$this->execution_start_time = microtime_float();
|
| 1502 |
-
}
|
| 1503 |
-
|
| 1504 |
-
function execution_time(){
|
| 1505 |
-
return microtime_float() - $this->execution_start_time;
|
| 1506 |
-
}
|
| 1507 |
-
|
| 1508 |
-
/**
|
| 1509 |
-
* ws_broken_link_checker::work()
|
| 1510 |
-
* The main worker function that does all kinds of things.
|
| 1511 |
-
*
|
| 1512 |
-
* @return void
|
| 1513 |
-
*/
|
| 1514 |
-
function work(){
|
| 1515 |
-
global $wpdb;
|
| 1516 |
-
|
| 1517 |
-
if ( !$this->acquire_lock() ){
|
| 1518 |
-
//FB::warn("Another instance of BLC is already working. Stop.");
|
| 1519 |
-
return false;
|
| 1520 |
-
}
|
| 1521 |
-
|
| 1522 |
-
$this->start_timer();
|
| 1523 |
-
|
| 1524 |
-
$max_execution_time = $this->options['max_execution_time'];
|
| 1525 |
-
|
| 1526 |
-
/*****************************************
|
| 1527 |
-
Preparation
|
| 1528 |
-
******************************************/
|
| 1529 |
-
// Check for safe mode
|
| 1530 |
-
if( ini_get('safe_mode') ){
|
| 1531 |
-
// Do it the safe mode way
|
| 1532 |
-
$t=ini_get('max_execution_time');
|
| 1533 |
-
if ($t && ($t < $max_execution_time))
|
| 1534 |
-
$max_execution_time = $t-1;
|
| 1535 |
-
} else {
|
| 1536 |
-
// Do it the regular way
|
| 1537 |
-
@set_time_limit( $max_execution_time * 2 ); //x2 should be plenty, running any longer would mean a glitch.
|
| 1538 |
-
}
|
| 1539 |
-
@ignore_user_abort(true);
|
| 1540 |
-
|
| 1541 |
-
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->options['check_threshold'].' hours'));
|
| 1542 |
-
$recheck_threshold = date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
| 1543 |
-
|
| 1544 |
-
$orphans_possible = false;
|
| 1545 |
-
|
| 1546 |
-
$still_need_resynch = $this->options['need_resynch'];
|
| 1547 |
-
|
| 1548 |
-
/*****************************************
|
| 1549 |
-
Parse posts and bookmarks
|
| 1550 |
-
******************************************/
|
| 1551 |
-
|
| 1552 |
-
if ( $this->options['need_resynch'] ) {
|
| 1553 |
-
|
| 1554 |
-
//FB::log("Looking for posts and bookmarks that need parsing...");
|
| 1555 |
-
|
| 1556 |
-
$tsynch = $wpdb->prefix.'blc_synch';
|
| 1557 |
-
$tposts = $wpdb->posts;
|
| 1558 |
-
$tlinks = $wpdb->links;
|
| 1559 |
-
|
| 1560 |
-
$synch_q = "SELECT $tsynch.source_id, $tsynch.source_type, $tposts.post_content, $tlinks.link_url, $tlinks.link_id, $tlinks.link_name
|
| 1561 |
-
|
| 1562 |
-
FROM
|
| 1563 |
-
$tsynch LEFT JOIN $tposts
|
| 1564 |
-
ON ($tposts.id = $tsynch.source_id AND $tsynch.source_type='post')
|
| 1565 |
-
LEFT JOIN $tlinks
|
| 1566 |
-
ON ($tlinks.link_id = $tsynch.source_id AND $tsynch.source_type='blogroll')
|
| 1567 |
-
|
| 1568 |
-
WHERE
|
| 1569 |
-
$tsynch.synched = 0
|
| 1570 |
-
|
| 1571 |
-
LIMIT 50";
|
| 1572 |
-
|
| 1573 |
-
while ( $rows = $wpdb->get_results($synch_q, ARRAY_A) ) {
|
| 1574 |
-
|
| 1575 |
-
//FB::log("Found ".count($rows)." items to analyze.");
|
| 1576 |
-
|
| 1577 |
-
foreach ($rows as $row) {
|
| 1578 |
-
|
| 1579 |
-
if ( $row['source_type'] == 'post' ){
|
| 1580 |
-
|
| 1581 |
-
//FB::log("Parsing post ".$row['source_id']);
|
| 1582 |
-
|
| 1583 |
-
//Remove instances associated with this post
|
| 1584 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1585 |
-
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
| 1586 |
-
$q = $wpdb->prepare($q, intval($row['source_id']));
|
| 1587 |
-
|
| 1588 |
-
//FB::log($q, "Executing query");
|
| 1589 |
-
|
| 1590 |
-
if ( $wpdb->query( $q ) === false ){
|
| 1591 |
-
//FB::error($wpdb->last_error, "Database error");
|
| 1592 |
-
}
|
| 1593 |
-
|
| 1594 |
-
//Gather links and images from the post
|
| 1595 |
-
$this->parse_post( $row['post_content'], $row['source_id'] );
|
| 1596 |
-
//Gather links from custom fields
|
| 1597 |
-
$this->parse_post_meta( $row['source_id'] );
|
| 1598 |
-
|
| 1599 |
-
//Some link records might be orhpaned now
|
| 1600 |
-
$orphans_possible = true;
|
| 1601 |
-
|
| 1602 |
-
} else {
|
| 1603 |
-
|
| 1604 |
-
//FB::log("Parsing bookmark ".$row['source_id']);
|
| 1605 |
-
|
| 1606 |
-
//Remove instances associated with this bookmark
|
| 1607 |
-
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1608 |
-
WHERE source_id = %d AND source_type = 'blogroll'";
|
| 1609 |
-
$q = $wpdb->prepare($q, intval($row['source_id']));
|
| 1610 |
-
//FB::log($q, "Executing query");
|
| 1611 |
-
|
| 1612 |
-
if ( $wpdb->query( $q ) === false ){
|
| 1613 |
-
//FB::error($wpdb->last_error, "Database error");
|
| 1614 |
-
}
|
| 1615 |
-
|
| 1616 |
-
//(Re)add the instance and link
|
| 1617 |
-
$this->parse_blogroll_link( $row );
|
| 1618 |
-
|
| 1619 |
-
//Some link records might be orhpaned now
|
| 1620 |
-
$orphans_possible = true;
|
| 1621 |
-
|
| 1622 |
-
}
|
| 1623 |
-
|
| 1624 |
-
//Update the table to indicate the item has been parsed
|
| 1625 |
-
$this->mark_synched( $row['source_id'], $row['source_type'] );
|
| 1626 |
-
|
| 1627 |
-
//Check if we still have some execution time left
|
| 1628 |
-
if( $this->execution_time() > $max_execution_time ){
|
| 1629 |
-
//FB::log('The alloted execution time has run out');
|
| 1630 |
-
$this->cleanup_links();
|
| 1631 |
-
$this->release_lock();
|
| 1632 |
-
return;
|
| 1633 |
-
}
|
| 1634 |
-
|
| 1635 |
-
}
|
| 1636 |
-
|
| 1637 |
-
}
|
| 1638 |
-
|
| 1639 |
-
//FB::log('No unparsed items found.');
|
| 1640 |
-
$still_need_resynch = false;
|
| 1641 |
-
|
| 1642 |
-
if ( $wpdb->last_error ){
|
| 1643 |
-
//FB::error($wpdb->last_error, "Database error");
|
| 1644 |
-
}
|
| 1645 |
-
|
| 1646 |
-
} else {
|
| 1647 |
-
//FB::log('Resynch not required.');
|
| 1648 |
-
}
|
| 1649 |
-
|
| 1650 |
-
/******************************************
|
| 1651 |
-
Resynch done?
|
| 1652 |
-
*******************************************/
|
| 1653 |
-
if ( $this->options['need_resynch'] && !$still_need_resynch ){
|
| 1654 |
-
$this->options['need_resynch'] = $still_need_resynch;
|
| 1655 |
-
$this->save_options();
|
| 1656 |
-
}
|
| 1657 |
-
|
| 1658 |
-
/******************************************
|
| 1659 |
-
Remove orphaned links
|
| 1660 |
-
*******************************************/
|
| 1661 |
-
|
| 1662 |
-
if ( $orphans_possible ) {
|
| 1663 |
-
//FB::log('Cleaning up the link table.');
|
| 1664 |
-
$this->cleanup_links();
|
| 1665 |
-
}
|
| 1666 |
-
|
| 1667 |
-
//Check if we still have some execution time left
|
| 1668 |
-
if( $this->execution_time() > $max_execution_time ){
|
| 1669 |
-
//FB::log('The alloted execution time has run out');
|
| 1670 |
-
$this->release_lock();
|
| 1671 |
-
return;
|
| 1672 |
-
}
|
| 1673 |
-
|
| 1674 |
-
/*****************************************
|
| 1675 |
-
Check links
|
| 1676 |
-
******************************************/
|
| 1677 |
-
//FB::log('Looking for links to check (threshold : '.$check_threshold.')...');
|
| 1678 |
-
|
| 1679 |
-
//Select some links that haven't been checked for a long time or
|
| 1680 |
-
//that are broken and need to be re-checked again.
|
| 1681 |
-
|
| 1682 |
-
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
| 1683 |
-
//I could put an index on last_check, but that value is almost certainly unique
|
| 1684 |
-
//for each row so it wouldn't be much better than a full table scan.
|
| 1685 |
-
$q = "SELECT *, ( last_check < %s ) AS meets_check_threshold
|
| 1686 |
-
FROM {$wpdb->prefix}blc_links
|
| 1687 |
-
WHERE
|
| 1688 |
-
( last_check < %s )
|
| 1689 |
-
OR
|
| 1690 |
-
(
|
| 1691 |
-
( http_code >= 400 OR http_code < 200 OR timeout = 1)
|
| 1692 |
-
AND check_count < %d
|
| 1693 |
-
AND check_count > 0
|
| 1694 |
-
AND last_check < %s
|
| 1695 |
-
)
|
| 1696 |
-
ORDER BY last_check ASC
|
| 1697 |
-
LIMIT 50";
|
| 1698 |
-
$link_q = $wpdb->prepare($q, $check_threshold, $check_threshold, $this->options['recheck_count'], $recheck_threshold);
|
| 1699 |
-
//FB::log($link_q);
|
| 1700 |
-
|
| 1701 |
-
while ( $links = $wpdb->get_results($link_q, ARRAY_A) ){
|
| 1702 |
-
|
| 1703 |
-
//some unchecked links found
|
| 1704 |
-
//FB::log("Checking ".count($links)." link(s)");
|
| 1705 |
-
|
| 1706 |
-
foreach ($links as $link) {
|
| 1707 |
-
$link_obj = new blcLink($link);
|
| 1708 |
-
|
| 1709 |
-
//Does this link need to be checked?
|
| 1710 |
-
if ( !$this->is_excluded( $link['url'] ) ) {
|
| 1711 |
-
//Yes, do it
|
| 1712 |
-
//FB::log("Checking link {$link[link_id]}");
|
| 1713 |
-
$link_obj->check();
|
| 1714 |
-
$link_obj->save();
|
| 1715 |
-
} else {
|
| 1716 |
-
//Nope, mark it as already checked.
|
| 1717 |
-
//FB::info("The URL {$link_obj->url} is excluded, marking link {$link_obj->link_id} as already checked.");
|
| 1718 |
-
$link_obj->last_check = date('Y-m-d H:i:s');
|
| 1719 |
-
$link_obj->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
| 1720 |
-
$link_obj->timeout = false;
|
| 1721 |
-
$link_obj->request_duration = 0;
|
| 1722 |
-
$link_obj->log = "This link wasn't checked because a matching keyword was found on your exclusion list.";
|
| 1723 |
-
$link_obj->save();
|
| 1724 |
-
}
|
| 1725 |
-
|
| 1726 |
-
//Check if we still have some execution time left
|
| 1727 |
-
if( $this->execution_time() > $max_execution_time ){
|
| 1728 |
-
//FB::log('The alloted execution time has run out');
|
| 1729 |
-
$this->release_lock();
|
| 1730 |
-
return;
|
| 1731 |
-
}
|
| 1732 |
-
}
|
| 1733 |
-
}
|
| 1734 |
-
//FB::log('No links need to be checked right now.');
|
| 1735 |
-
|
| 1736 |
-
$this->release_lock();
|
| 1737 |
-
//FB::log('All done.');
|
| 1738 |
-
}
|
| 1739 |
-
|
| 1740 |
-
function ajax_full_status( ){
|
| 1741 |
-
$status = $this->get_status();
|
| 1742 |
-
$text = $this->status_text( $status );
|
| 1743 |
-
|
| 1744 |
-
echo json_encode( array(
|
| 1745 |
-
'text' => $text,
|
| 1746 |
-
'status' => $status,
|
| 1747 |
-
) );
|
| 1748 |
-
|
| 1749 |
-
die();
|
| 1750 |
-
}
|
| 1751 |
-
|
| 1752 |
-
/**
|
| 1753 |
-
* ws_broken_link_checker::status_text()
|
| 1754 |
-
* Generates a status message based on the status info in $status
|
| 1755 |
-
*
|
| 1756 |
-
* @param array $status
|
| 1757 |
-
* @return string
|
| 1758 |
-
*/
|
| 1759 |
-
function status_text( $status ){
|
| 1760 |
-
$text = '';
|
| 1761 |
-
|
| 1762 |
-
if( $status['broken_links'] > 0 ){
|
| 1763 |
-
$text .= sprintf( "<a href='%stools.php?page=view-broken-links' title='View broken links'><strong>Found %d broken link%s</strong></a>",
|
| 1764 |
-
get_option('wpurl'), $status['broken_links'], ( $status['broken_links'] == 1 )?'':'s' );
|
| 1765 |
-
} else {
|
| 1766 |
-
$text .= "No broken links found.";
|
| 1767 |
-
}
|
| 1768 |
-
|
| 1769 |
-
$text .= "<br/>";
|
| 1770 |
-
|
| 1771 |
-
if( $status['unchecked_links'] > 0) {
|
| 1772 |
-
$text .= sprintf( '%d URL%s in the work queue', $status['unchecked_links'], ($status['unchecked_links'] == 1)?'':'s' );
|
| 1773 |
-
} else {
|
| 1774 |
-
$text .= "No URLs in the work queue.";
|
| 1775 |
-
}
|
| 1776 |
-
|
| 1777 |
-
$text .= "<br/>";
|
| 1778 |
-
if ( $status['known_links'] > 0 ){
|
| 1779 |
-
$text .= sprintf( "Detected %d unique URL%s in %d link%s",
|
| 1780 |
-
$status['known_links'], $status['known_links'] == 1 ? '' : 's',
|
| 1781 |
-
$status['known_instances'], $status['known_instances'] == 1 ? '' : 's'
|
| 1782 |
-
);
|
| 1783 |
-
if ($this->options['need_resynch']){
|
| 1784 |
-
$text .= ' and still searching...';
|
| 1785 |
-
} else {
|
| 1786 |
-
$text .= '.';
|
| 1787 |
-
}
|
| 1788 |
-
} else {
|
| 1789 |
-
if ($this->options['need_resynch']){
|
| 1790 |
-
$text .= 'Searching your blog for links...';
|
| 1791 |
-
} else {
|
| 1792 |
-
$text .= 'No links detected.';
|
| 1793 |
-
}
|
| 1794 |
-
}
|
| 1795 |
-
|
| 1796 |
-
return $text;
|
| 1797 |
-
}
|
| 1798 |
-
|
| 1799 |
-
function ajax_dashboard_status(){
|
| 1800 |
-
//Just display the full status.
|
| 1801 |
-
$this->ajax_full_status( false );
|
| 1802 |
-
/*
|
| 1803 |
-
global $wpdb;
|
| 1804 |
-
|
| 1805 |
-
//displays a notification if broken links have been found
|
| 1806 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1807 |
-
WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 )";
|
| 1808 |
-
$broken_links = $wpdb->get_var($q);
|
| 1809 |
-
|
| 1810 |
-
|
| 1811 |
-
if($broken_links>0){
|
| 1812 |
-
printf( "<a href='%stools.php?page=view-broken-links' title='View broken links'><strong>Found %d broken link%s</strong></a>",
|
| 1813 |
-
get_option('wpurl'), $broken_links, ($broken_links==1)?'':'s' );
|
| 1814 |
-
} else {
|
| 1815 |
-
echo "No broken links found.";
|
| 1816 |
-
}
|
| 1817 |
-
die();
|
| 1818 |
-
*/
|
| 1819 |
-
}
|
| 1820 |
-
|
| 1821 |
-
/**
|
| 1822 |
-
* ws_broken_link_checker::get_status()
|
| 1823 |
-
* Returns an array with various status information about the plugin. Array key reference:
|
| 1824 |
-
* check_threshold - date/time; links checked before this threshold should be checked again.
|
| 1825 |
-
* recheck_threshold - date/time; broken links checked before this threshold should be re-checked.
|
| 1826 |
-
* known_links - the number of detected unique URLs (a misleading name, yes).
|
| 1827 |
-
* known_instances - the number of detected link instances, i.e. actual link elements in posts and other places.
|
| 1828 |
-
* broken_links - the number of detected broken links.
|
| 1829 |
-
* unchecked_links - the number of URLs that need to be checked ASAP; based on check_threshold and recheck_threshold.
|
| 1830 |
-
*
|
| 1831 |
-
* @return array
|
| 1832 |
-
*/
|
| 1833 |
-
function get_status(){
|
| 1834 |
-
global $wpdb;
|
| 1835 |
-
|
| 1836 |
-
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->options['check_threshold'].' hours'));
|
| 1837 |
-
$recheck_threshold=date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
| 1838 |
-
|
| 1839 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links WHERE 1";
|
| 1840 |
-
$known_links = $wpdb->get_var($q);
|
| 1841 |
-
|
| 1842 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_instances WHERE 1";
|
| 1843 |
-
$known_instances = $wpdb->get_var($q);
|
| 1844 |
-
|
| 1845 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1846 |
-
WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( http_code <> ".BLC_CHECKING." )";
|
| 1847 |
-
$broken_links = $wpdb->get_var($q);
|
| 1848 |
-
|
| 1849 |
-
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1850 |
-
WHERE
|
| 1851 |
-
( ( last_check < '$check_threshold' ) OR
|
| 1852 |
-
(
|
| 1853 |
-
( http_code >= 400 OR http_code < 200 )
|
| 1854 |
-
AND check_count < 3
|
| 1855 |
-
AND last_check < '$recheck_threshold' )
|
| 1856 |
-
)";
|
| 1857 |
-
$unchecked_links = $wpdb->get_var($q);
|
| 1858 |
-
|
| 1859 |
-
return array(
|
| 1860 |
-
'check_threshold' => $check_threshold,
|
| 1861 |
-
'recheck_threshold' => $recheck_threshold,
|
| 1862 |
-
'known_links' => $known_links,
|
| 1863 |
-
'known_instances' => $known_instances,
|
| 1864 |
-
'broken_links' => $broken_links,
|
| 1865 |
-
'unchecked_links' => $unchecked_links,
|
| 1866 |
-
);
|
| 1867 |
-
}
|
| 1868 |
-
|
| 1869 |
-
function ajax_work(){
|
| 1870 |
-
//Run the worker function
|
| 1871 |
-
$this->work();
|
| 1872 |
-
die();
|
| 1873 |
-
}
|
| 1874 |
-
|
| 1875 |
-
function ajax_discard(){
|
| 1876 |
-
//TODO:Rewrite to use JSON instead of plaintext
|
| 1877 |
-
if (!current_user_can('edit_others_posts')){
|
| 1878 |
-
die( "You're not allowed to do that!" );
|
| 1879 |
-
}
|
| 1880 |
-
|
| 1881 |
-
if ( isset($_POST['link_id']) ){
|
| 1882 |
-
//Load the link
|
| 1883 |
-
$link = new blcLink( intval($_POST['link_id']) );
|
| 1884 |
-
|
| 1885 |
-
if ( !$link->valid() ){
|
| 1886 |
-
die("Oops, I can't find the link ".intval($_POST['link_id']) );
|
| 1887 |
-
}
|
| 1888 |
-
//Make it appear "not broken"
|
| 1889 |
-
$link->last_check = date('Y-m-d H:i:s');
|
| 1890 |
-
$link->http_code = 200;
|
| 1891 |
-
$link->timeout = 0;
|
| 1892 |
-
$link->check_count = 0;
|
| 1893 |
-
$link->log = "This link was manually marked as working by the user.";
|
| 1894 |
-
|
| 1895 |
-
//Save the changes
|
| 1896 |
-
if ( $link->save() ){
|
| 1897 |
-
die("OK");
|
| 1898 |
-
} else {
|
| 1899 |
-
die("Oops, couldn't modify the link!");
|
| 1900 |
-
}
|
| 1901 |
-
} else {
|
| 1902 |
-
die("Error : link_id not specified");
|
| 1903 |
-
}
|
| 1904 |
-
}
|
| 1905 |
-
|
| 1906 |
-
function ajax_edit(){
|
| 1907 |
-
if (!current_user_can('edit_others_posts')){
|
| 1908 |
-
die( json_encode( array(
|
| 1909 |
-
'error' => "You're not allowed to do that!"
|
| 1910 |
-
)));
|
| 1911 |
-
}
|
| 1912 |
-
|
| 1913 |
-
if ( isset($_GET['link_id']) && !empty($_GET['new_url']) ){
|
| 1914 |
-
//Load the link
|
| 1915 |
-
$link = new blcLink( intval($_GET['link_id']) );
|
| 1916 |
-
|
| 1917 |
-
if ( !$link->valid() ){
|
| 1918 |
-
die( json_encode( array(
|
| 1919 |
-
'error' => "Oops, I can't find the link ".intval($_GET['link_id'])
|
| 1920 |
-
)));
|
| 1921 |
-
}
|
| 1922 |
-
|
| 1923 |
-
$new_url = blcUtility::normalize_url($_GET['new_url']);
|
| 1924 |
-
if ( !$new_url ){
|
| 1925 |
-
die( json_encode( array(
|
| 1926 |
-
'error' => "Oops, the new URL is invalid!"
|
| 1927 |
-
)));
|
| 1928 |
-
}
|
| 1929 |
-
|
| 1930 |
-
//Try and edit the link
|
| 1931 |
-
$rez = $link->edit($new_url);
|
| 1932 |
-
|
| 1933 |
-
if ( $rez == false ){
|
| 1934 |
-
die( json_encode( array(
|
| 1935 |
-
'error' => "An unexpected error occured!"
|
| 1936 |
-
)));
|
| 1937 |
-
} else {
|
| 1938 |
-
$rez['ok'] = 'OK';
|
| 1939 |
-
die( json_encode($rez) );
|
| 1940 |
-
}
|
| 1941 |
-
|
| 1942 |
-
} else {
|
| 1943 |
-
die( json_encode( array(
|
| 1944 |
-
'error' => "Error : link_id or new_url not specified"
|
| 1945 |
-
)));
|
| 1946 |
-
}
|
| 1947 |
-
}
|
| 1948 |
-
|
| 1949 |
-
function ajax_unlink(){
|
| 1950 |
-
if (!current_user_can('edit_others_posts')){
|
| 1951 |
-
die( json_encode( array(
|
| 1952 |
-
'error' => "You're not allowed to do that!"
|
| 1953 |
-
)));
|
| 1954 |
-
}
|
| 1955 |
-
|
| 1956 |
-
if ( isset($_POST['link_id']) ){
|
| 1957 |
-
//Load the link
|
| 1958 |
-
$link = new blcLink( intval($_POST['link_id']) );
|
| 1959 |
-
|
| 1960 |
-
if ( !$link->valid() ){
|
| 1961 |
-
die( json_encode( array(
|
| 1962 |
-
'error' => "Oops, I can't find the link ".intval($_POST['link_id'])
|
| 1963 |
-
)));
|
| 1964 |
-
}
|
| 1965 |
-
|
| 1966 |
-
//Try and unlink it
|
| 1967 |
-
if ( $link->unlink() ){
|
| 1968 |
-
die( json_encode( array(
|
| 1969 |
-
'ok' => "URL {$link->url} was removed."
|
| 1970 |
-
)));
|
| 1971 |
-
} else {
|
| 1972 |
-
die( json_encode( array(
|
| 1973 |
-
'error' => "The plugin failed to remove the link."
|
| 1974 |
-
)));
|
| 1975 |
-
}
|
| 1976 |
-
|
| 1977 |
-
} else {
|
| 1978 |
-
die( json_encode( array(
|
| 1979 |
-
'error' => "Error : link_id not specified"
|
| 1980 |
-
)));
|
| 1981 |
-
}
|
| 1982 |
-
}
|
| 1983 |
-
|
| 1984 |
-
function ajax_link_details(){
|
| 1985 |
-
global $wpdb;
|
| 1986 |
-
|
| 1987 |
-
if (!current_user_can('edit_others_posts')){
|
| 1988 |
-
die("You don't have sufficient privileges to access this information!");
|
| 1989 |
-
}
|
| 1990 |
-
|
| 1991 |
-
//FB::log("Loading link details via AJAX");
|
| 1992 |
-
|
| 1993 |
-
if ( isset($_GET['link_id']) ){
|
| 1994 |
-
//FB::info("Link ID found in GET");
|
| 1995 |
-
$link_id = intval($_GET['link_id']);
|
| 1996 |
-
} else if ( isset($_POST['link_id']) ){
|
| 1997 |
-
//FB::info("Link ID found in POST");
|
| 1998 |
-
$link_id = intval($_POST['link_id']);
|
| 1999 |
-
} else {
|
| 2000 |
-
//FB::error('Link ID not specified, you hacking bastard.');
|
| 2001 |
-
die('Error : link ID not specified');
|
| 2002 |
-
}
|
| 2003 |
-
|
| 2004 |
-
//Load the link. link_details_row needs it as an array, so
|
| 2005 |
-
//we'll have to do this the long way.
|
| 2006 |
-
$q = "SELECT
|
| 2007 |
-
links.*,
|
| 2008 |
-
COUNT(*) as instance_count
|
| 2009 |
-
|
| 2010 |
-
FROM
|
| 2011 |
-
{$wpdb->prefix}blc_links AS links,
|
| 2012 |
-
{$wpdb->prefix}blc_instances as instances
|
| 2013 |
-
|
| 2014 |
-
WHERE
|
| 2015 |
-
links.link_id = %d
|
| 2016 |
-
|
| 2017 |
-
GROUP BY links.link_id";
|
| 2018 |
-
|
| 2019 |
-
$link = $wpdb->get_row( $wpdb->prepare($q, $link_id), ARRAY_A );
|
| 2020 |
-
if ( is_array($link) ){
|
| 2021 |
-
//FB::info($link, 'Link loaded');
|
| 2022 |
-
$this->link_details_row($link);
|
| 2023 |
-
die();
|
| 2024 |
-
} else {
|
| 2025 |
-
die ("Failed to load link details (" . $wpdb->last_error . ")");
|
| 2026 |
-
}
|
| 2027 |
-
}
|
| 2028 |
-
|
| 2029 |
-
function ajax_exclude_link(){
|
| 2030 |
-
if ( !current_user_can('manage_options') ){
|
| 2031 |
-
die( json_encode( array(
|
| 2032 |
-
'error' => "You're not allowed to do that!"
|
| 2033 |
-
)));
|
| 2034 |
-
}
|
| 2035 |
-
|
| 2036 |
-
if ( isset($_POST['link_id']) ){
|
| 2037 |
-
//Load the link
|
| 2038 |
-
$link = new blcLink( intval($_POST['link_id']) );
|
| 2039 |
-
|
| 2040 |
-
if ( !$link->valid() ){
|
| 2041 |
-
die( json_encode( array(
|
| 2042 |
-
'error' => "Oops, I can't find the link ".intval($_POST['link_id'])
|
| 2043 |
-
)));
|
| 2044 |
-
}
|
| 2045 |
-
|
| 2046 |
-
//Add the URL to the exclusion list
|
| 2047 |
-
if ( !in_array( $link->url, $this->options['exclusion_list'] ) ){
|
| 2048 |
-
$this->options['exclusion_list'][] = $link->url;
|
| 2049 |
-
//Also mark it as already checked so that it doesn't show up with other broken links.
|
| 2050 |
-
//FB::info("The URL {$link->url} is excluded, marking link {$link->link_id} as already checked.");
|
| 2051 |
-
$link->last_check = date('Y-m-d H:i:s');
|
| 2052 |
-
$link->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
| 2053 |
-
$link->timeout = false;
|
| 2054 |
-
$link->request_duration = 0;
|
| 2055 |
-
$link->log = "This link wasn't checked because a matching keyword was found on your exclusion list.";
|
| 2056 |
-
$link->save();
|
| 2057 |
-
}
|
| 2058 |
-
|
| 2059 |
-
$this->save_options();
|
| 2060 |
-
|
| 2061 |
-
die( json_encode( array(
|
| 2062 |
-
'ok' => "URL {$link->url} added to the exclusion list"
|
| 2063 |
-
)));
|
| 2064 |
-
} else {
|
| 2065 |
-
die( json_encode( array(
|
| 2066 |
-
'error' => "Link ID not specified"
|
| 2067 |
-
)));
|
| 2068 |
-
}
|
| 2069 |
-
}
|
| 2070 |
-
|
| 2071 |
-
/**
|
| 2072 |
-
* ws_broken_link_checker::acquire_lock()
|
| 2073 |
-
* Create and lock a temporary file.
|
| 2074 |
-
*
|
| 2075 |
-
* @return bool
|
| 2076 |
-
*/
|
| 2077 |
-
function acquire_lock(){
|
| 2078 |
-
//Maybe we already have the lock?
|
| 2079 |
-
if ( $this->lockfile_handle ){
|
| 2080 |
-
return true;
|
| 2081 |
-
}
|
| 2082 |
-
|
| 2083 |
-
$fn = $this->lockfile_name();
|
| 2084 |
-
if ( $fn ){
|
| 2085 |
-
//Open the lockfile
|
| 2086 |
-
$this->lockfile_handle = fopen($fn, 'w+');
|
| 2087 |
-
if ( $this->lockfile_handle ){
|
| 2088 |
-
//Do an exclusive lock
|
| 2089 |
-
if (flock($this->lockfile_handle, LOCK_EX | LOCK_NB)) {
|
| 2090 |
-
//File locked successfully
|
| 2091 |
-
return true;
|
| 2092 |
-
} else {
|
| 2093 |
-
//Something went wrong
|
| 2094 |
-
fclose($this->lockfile_handle);
|
| 2095 |
-
$this->lockfile_handle = null;
|
| 2096 |
-
return false;
|
| 2097 |
-
}
|
| 2098 |
-
} else {
|
| 2099 |
-
//Can't open the file, fail.
|
| 2100 |
-
return false;
|
| 2101 |
-
}
|
| 2102 |
-
} else {
|
| 2103 |
-
//Uh oh, can't generate a lockfile name. Locking will be disabled.
|
| 2104 |
-
return true;
|
| 2105 |
-
};
|
| 2106 |
-
}
|
| 2107 |
-
|
| 2108 |
-
/**
|
| 2109 |
-
* ws_broken_link_checker::release_lock()
|
| 2110 |
-
* Unlock and delete the temporary file
|
| 2111 |
-
*
|
| 2112 |
-
* @return bool
|
| 2113 |
-
*/
|
| 2114 |
-
function release_lock(){
|
| 2115 |
-
if ( $this->lockfile_handle ){
|
| 2116 |
-
//Close the file (implicitly releasing the lock)
|
| 2117 |
-
fclose( $this->lockfile_handle );
|
| 2118 |
-
//Delete the file
|
| 2119 |
-
$fn = $this->lockfile_name();
|
| 2120 |
-
if ( file_exists( $fn ) ) {
|
| 2121 |
-
unlink( $fn );
|
| 2122 |
-
}
|
| 2123 |
-
$this->lockfile_handle = null;
|
| 2124 |
-
return true;
|
| 2125 |
-
} else {
|
| 2126 |
-
//We didn't have the lock anyway...
|
| 2127 |
-
return false;
|
| 2128 |
-
}
|
| 2129 |
-
}
|
| 2130 |
-
|
| 2131 |
-
/**
|
| 2132 |
-
* ws_broken_link_checker::lockfile_name()
|
| 2133 |
-
* Generate system-specific lockfile filename
|
| 2134 |
-
*
|
| 2135 |
-
* @return string A filename or FALSE on error
|
| 2136 |
-
*/
|
| 2137 |
-
function lockfile_name(){
|
| 2138 |
-
//Try the plugin's directory first.
|
| 2139 |
-
if ( is_writable( dirname(__FILE__) ) ){
|
| 2140 |
-
return dirname(__FILE__) . '/wp_blc_lock';
|
| 2141 |
-
} else {
|
| 2142 |
-
//Try to find the temp directory.
|
| 2143 |
-
$dummy = tempnam('asdf', 'blc');
|
| 2144 |
-
if ( $dummy ) {
|
| 2145 |
-
$path = dirname($dummy);
|
| 2146 |
-
//Kill the dummy file
|
| 2147 |
-
if ( file_exists( $dummy ) ) unlink($dummy);
|
| 2148 |
-
return $path . '/wp_blc_lock';
|
| 2149 |
-
} else {
|
| 2150 |
-
//Try /tmp as a last resort
|
| 2151 |
-
if ( is_writable('/tmp') ){
|
| 2152 |
-
return '/tmp/wp_blc_lock';
|
| 2153 |
-
} else {
|
| 2154 |
-
return false;
|
| 2155 |
-
}
|
| 2156 |
-
}
|
| 2157 |
-
}
|
| 2158 |
-
}
|
| 2159 |
-
|
| 2160 |
-
function hook_add_link( $link_id ){
|
| 2161 |
-
$this->mark_unsynched( $link_id, 'blogroll' );
|
| 2162 |
-
}
|
| 2163 |
-
|
| 2164 |
-
function hook_edit_link( $link_id ){
|
| 2165 |
-
$this->mark_unsynched( $link_id, 'blogroll' );
|
| 2166 |
-
}
|
| 2167 |
-
|
| 2168 |
-
function hook_delete_link( $link_id ){
|
| 2169 |
-
global $wpdb;
|
| 2170 |
-
//Delete the synch record
|
| 2171 |
-
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}blc_synch WHERE source_id = %d AND source_type='blogroll'", $link_id ) );
|
| 2172 |
-
|
| 2173 |
-
//Get the matching instance record.
|
| 2174 |
-
$inst = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE source_id = %d AND source_type = 'blogroll'", $link_id), ARRAY_A );
|
| 2175 |
-
|
| 2176 |
-
if ( !$inst ) {
|
| 2177 |
-
//No instance record? No problem.
|
| 2178 |
-
return;
|
| 2179 |
-
}
|
| 2180 |
-
|
| 2181 |
-
//Remove it
|
| 2182 |
-
$wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id = %d", $inst['instance_id']) );
|
| 2183 |
-
|
| 2184 |
-
//Remove the link that was associated with this instance if it has no more related instances.
|
| 2185 |
-
$this->cleanup_links( $inst['link_id'] );
|
| 2186 |
-
}
|
| 2187 |
-
|
| 2188 |
-
function hook_wp_dashboard_setup(){
|
| 2189 |
-
if ( function_exists( 'wp_add_dashboard_widget' ) ) {
|
| 2190 |
-
wp_add_dashboard_widget(
|
| 2191 |
-
'blc_dashboard_widget',
|
| 2192 |
-
'Broken Link Checker',
|
| 2193 |
-
array( &$this, 'dashboard_widget' ),
|
| 2194 |
-
array( &$this, 'dashboard_widget_control' )
|
| 2195 |
-
);
|
| 2196 |
-
}
|
| 2197 |
-
}
|
| 2198 |
-
|
| 2199 |
-
}//class ends here
|
| 2200 |
-
|
| 2201 |
-
} // if class_exists...
|
| 2202 |
-
|
| 2203 |
-
if ( !isset($ws_link_checker) )
|
| 2204 |
-
$ws_link_checker = new ws_broken_link_checker();
|
| 2205 |
-
|
| 2206 |
?>
|
| 1 |
<?php
|
| 2 |
+
|
| 3 |
/*
|
| 4 |
Plugin Name: Broken Link Checker
|
| 5 |
Plugin URI: http://w-shadow.com/blog/2007/08/05/broken-link-checker-for-wordpress/
|
| 6 |
Description: Checks your posts for broken links and missing images and notifies you on the dashboard if any are found.
|
| 7 |
+
Version: 0.5.10
|
| 8 |
Author: Janis Elsts
|
| 9 |
Author URI: http://w-shadow.com/blog/
|
| 10 |
*/
|
| 14 |
MySQL 4.0 compatibility by Jeroen (www.yukka.eu)
|
| 15 |
*/
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
/*
|
| 18 |
//FirePHP for debugging
|
| 19 |
if ( !class_exists('FB') ) {
|
| 25 |
//to uncomment : \/\/(\s*FB::) -> $1
|
| 26 |
//*/
|
| 27 |
|
| 28 |
+
//Make sure some useful constants are defined
|
| 29 |
+
if ( ! defined( 'WP_CONTENT_URL' ) )
|
| 30 |
+
define( 'WP_CONTENT_URL', get_option( 'siteurl' ) . '/wp-content' );
|
| 31 |
+
if ( ! defined( 'WP_CONTENT_DIR' ) )
|
| 32 |
+
define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
|
| 33 |
+
if ( ! defined( 'WP_PLUGIN_URL' ) )
|
| 34 |
+
define( 'WP_PLUGIN_URL', WP_CONTENT_URL. '/plugins' );
|
| 35 |
+
if ( ! defined( 'WP_PLUGIN_DIR' ) )
|
| 36 |
+
define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
//The HTTP code of a link record can be set to one of these in some special circumstances
|
| 39 |
+
if ( ! defined('BLC_CHECKING') )
|
| 40 |
+
define('BLC_CHECKING', 1); //The link is currently being checked. If this state persists, suspect a glitch.
|
| 41 |
+
if ( ! defined('BLC_TIMEOUT') )
|
| 42 |
+
define('BLC_TIMEOUT', 0); //The code used for links that timed out and didn't return an actual response.
|
| 43 |
+
|
| 44 |
+
//Load and initialize the plugin's configuration
|
| 45 |
+
require 'config-manager.php';
|
| 46 |
+
$blc_config_manager = new blcConfigurationManager(
|
| 47 |
+
//Save the plugin's configuration into this DB option
|
| 48 |
+
'wsblc_options',
|
| 49 |
+
//Initialize default settings
|
| 50 |
+
array(
|
| 51 |
+
'max_execution_time' => 5*60, //How long the worker instance may run, at most.
|
| 52 |
+
'check_threshold' => 72, //Check each link every 72 hours.
|
| 53 |
+
'mark_broken_links' => true, //Whether to add the broken_link class to broken links in posts.
|
| 54 |
+
'broken_link_css' => ".broken_link, a.broken_link {\n\ttext-decoration: line-through;\n}",
|
| 55 |
+
'exclusion_list' => array(), //Links that contain a substring listed in this array won't be checked.
|
| 56 |
+
'recheck_count' => 3, //[Internal] How many times a broken link should be re-checked (slightly buggy)
|
| 57 |
+
|
| 58 |
+
//These three are currently ignored. Everything is checked by default.
|
| 59 |
+
'check_posts' => true,
|
| 60 |
+
'check_custom_fields' => true,
|
| 61 |
+
'check_blogroll' => true,
|
| 62 |
+
|
| 63 |
+
'custom_fields' => array(), //List of custom fields that can contain URLs and should be checked.
|
| 64 |
+
|
| 65 |
+
'autoexpand_widget' => true, //Autoexpand the Dashboard widget if broken links are detected
|
| 66 |
+
|
| 67 |
+
'need_resynch' => false, //[Internal flag]
|
| 68 |
+
'current_db_version' => 0, //The current version of the plugin's tables
|
| 69 |
+
)
|
| 70 |
+
);
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
if ( !is_admin() ){
|
| 74 |
+
//This is user-side request, so the only thing we may need to do is run the broken link highlighter.
|
| 75 |
+
if ( $blc_config_manager->options['mark_broken_links'] ){
|
| 76 |
+
//Load some utilities (used by the higlighter) and the highlighter itself
|
| 77 |
+
require 'utility-class.php';
|
| 78 |
+
require 'highlighter-class.php';
|
| 79 |
+
$blc_link_highlighter = new blcLinkHighlighter( $blc_config_manager->options['broken_link_css'] );
|
| 80 |
+
}
|
| 81 |
+
} else {
|
| 82 |
+
//Load everything
|
| 83 |
+
require 'utility-class.php';
|
| 84 |
+
require 'instance-classes.php';
|
| 85 |
+
require 'link-classes.php';
|
| 86 |
+
require 'core.php';
|
| 87 |
+
|
| 88 |
+
$ws_link_checker = new wsBrokenLinkChecker( __FILE__ , $blc_config_manager );
|
| 89 |
}
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
?>
|
config-manager.php
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* @author W-Shadow
|
| 5 |
+
* @copyright 2009
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
class blcConfigurationManager {
|
| 9 |
+
|
| 10 |
+
var $option_name;
|
| 11 |
+
|
| 12 |
+
var $options;
|
| 13 |
+
var $defaults;
|
| 14 |
+
var $loaded_values;
|
| 15 |
+
|
| 16 |
+
function blcConfigurationManager( $option_name = '', $default_settings = null ){
|
| 17 |
+
$this->option_name = $option_name;
|
| 18 |
+
|
| 19 |
+
if ( is_array($default_settings) ){
|
| 20 |
+
$this->defaults = $default_settings;
|
| 21 |
+
} else {
|
| 22 |
+
$this->defaults = array();
|
| 23 |
+
}
|
| 24 |
+
$this->loaded_values = array();
|
| 25 |
+
|
| 26 |
+
$this->options = $this->defaults;
|
| 27 |
+
|
| 28 |
+
if ( !empty( $this->option_name ) )
|
| 29 |
+
$this->load_options();
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
function set_defaults( $default_settings = null ){
|
| 33 |
+
if ( is_array($default_settings) ){
|
| 34 |
+
$this->defaults = array();
|
| 35 |
+
} else {
|
| 36 |
+
$this->defaults = $default_settings;
|
| 37 |
+
}
|
| 38 |
+
$this->options = array_merge($this->defaults, $this->loaded_values);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
/**
|
| 42 |
+
* blcOptionManager::load_options()
|
| 43 |
+
* Load plugin options from the database. The current $options values are not affected
|
| 44 |
+
* if this function fails.
|
| 45 |
+
*
|
| 46 |
+
* @param string $option_name
|
| 47 |
+
* @return bool True if options were loaded, false otherwise.
|
| 48 |
+
*/
|
| 49 |
+
function load_options( $option_name = '' ){
|
| 50 |
+
if ( !empty($option_name) ){
|
| 51 |
+
$this->option_name = $option_name;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
if ( empty($this->option_name) ) return false;
|
| 55 |
+
|
| 56 |
+
$new_options = get_option($this->option_name);
|
| 57 |
+
if( !is_array( $new_options ) ){
|
| 58 |
+
return false;
|
| 59 |
+
} else {
|
| 60 |
+
$this->loaded_values = $new_options;
|
| 61 |
+
$this->options = array_merge( $this->defaults, $this->loaded_values );
|
| 62 |
+
return true;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/**
|
| 67 |
+
* blcOptionManager::save_options()
|
| 68 |
+
* Save plugin options to the databse.
|
| 69 |
+
*
|
| 70 |
+
* @param string $option_name (Optional) Save the options under this name
|
| 71 |
+
* @return bool True on success, false on failure
|
| 72 |
+
*/
|
| 73 |
+
function save_options( $option_name = '' ){
|
| 74 |
+
if ( !empty($option_name) ){
|
| 75 |
+
$this->option_name = $option_name;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
if ( empty($this->option_name) ) return false;
|
| 79 |
+
|
| 80 |
+
update_option( $this->option_name, $this->options );
|
| 81 |
+
return true;
|
| 82 |
+
}
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
?>
|
core.php
ADDED
|
@@ -0,0 +1,2137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
//The plugin will use Snoopy in case CURL is not available
|
| 4 |
+
if (!class_exists('Snoopy')) require_once(ABSPATH.'/wp-includes/class-snoopy.php');
|
| 5 |
+
|
| 6 |
+
/**
|
| 7 |
+
* Simple function to replicate PHP 5 behaviour
|
| 8 |
+
*/
|
| 9 |
+
if ( !function_exists( 'microtime_float' ) ) {
|
| 10 |
+
function microtime_float()
|
| 11 |
+
{
|
| 12 |
+
list($usec, $sec) = explode(" ", microtime());
|
| 13 |
+
return ((float)$usec + (float)$sec);
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
if (!class_exists('ws_broken_link_checker')) {
|
| 18 |
+
|
| 19 |
+
class wsBrokenLinkChecker {
|
| 20 |
+
var $conf;
|
| 21 |
+
|
| 22 |
+
var $loader;
|
| 23 |
+
var $my_basename = '';
|
| 24 |
+
|
| 25 |
+
var $db_version = 2;
|
| 26 |
+
|
| 27 |
+
var $execution_start_time; //Used for a simple internal execution timer in start_timer()/execution_time()
|
| 28 |
+
var $lockfile_handle = null;
|
| 29 |
+
|
| 30 |
+
/**
|
| 31 |
+
* wsBrokenLinkChecker::wsBrokenLinkChecker()
|
| 32 |
+
* Class constructor
|
| 33 |
+
*
|
| 34 |
+
* @param string $loader The fully qualified filename of the loader script that WP identifies as the "main" plugin file.
|
| 35 |
+
* @param blcConfigurationManager $conf An instance of the configuration manager
|
| 36 |
+
* @return void
|
| 37 |
+
*/
|
| 38 |
+
function wsBrokenLinkChecker ( $loader, $conf ) {
|
| 39 |
+
global $wpdb;
|
| 40 |
+
|
| 41 |
+
$this->loader = $loader;
|
| 42 |
+
$this->conf = $conf;
|
| 43 |
+
|
| 44 |
+
add_action('activate_' . plugin_basename( $this->loader ), array(&$this,'activation'));
|
| 45 |
+
$this->my_basename = plugin_basename( $this->loader );
|
| 46 |
+
|
| 47 |
+
add_action('admin_menu', array(&$this,'admin_menu'));
|
| 48 |
+
|
| 49 |
+
//These hooks update the plugin's internal records when posts are added, deleted or modified.
|
| 50 |
+
add_action('delete_post', array(&$this,'post_deleted'));
|
| 51 |
+
add_action('save_post', array(&$this,'post_saved'));
|
| 52 |
+
|
| 53 |
+
//These do the same for (blogroll) links.
|
| 54 |
+
add_action('add_link', array(&$this,'hook_add_link'));
|
| 55 |
+
add_action('edit_link', array(&$this,'hook_edit_link'));
|
| 56 |
+
add_action('delete_link', array(&$this,'hook_delete_link'));
|
| 57 |
+
|
| 58 |
+
//Load jQuery on Dashboard pages (possibly redundant as WP already does that)
|
| 59 |
+
add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
|
| 60 |
+
|
| 61 |
+
//The dashboard widget
|
| 62 |
+
add_action('wp_dashboard_setup', array(&$this, 'hook_wp_dashboard_setup'));
|
| 63 |
+
|
| 64 |
+
//AJAXy hooks
|
| 65 |
+
//TODO: Check nonces in AJAX hooks
|
| 66 |
+
add_action( 'wp_ajax_blc_full_status', array(&$this,'ajax_full_status') );
|
| 67 |
+
add_action( 'wp_ajax_blc_dashboard_status', array(&$this,'ajax_dashboard_status') );
|
| 68 |
+
add_action( 'wp_ajax_blc_work', array(&$this,'ajax_work') );
|
| 69 |
+
add_action( 'wp_ajax_blc_discard', array(&$this,'ajax_discard') );
|
| 70 |
+
add_action( 'wp_ajax_blc_edit', array(&$this,'ajax_edit') );
|
| 71 |
+
add_action( 'wp_ajax_blc_link_details', array(&$this,'ajax_link_details') );
|
| 72 |
+
add_action( 'wp_ajax_blc_exclude_link', array(&$this,'ajax_exclude_link') );
|
| 73 |
+
add_action( 'wp_ajax_blc_unlink', array(&$this,'ajax_unlink') );
|
| 74 |
+
|
| 75 |
+
//Check if it's possible to create a lockfile and nag the user about it if not.
|
| 76 |
+
if ( $this->lockfile_name() ){
|
| 77 |
+
//Lockfiles work, so it's safe to enable the footer hook that will call the worker
|
| 78 |
+
//function via AJAX.
|
| 79 |
+
add_action('admin_footer', array(&$this,'admin_footer'));
|
| 80 |
+
} else {
|
| 81 |
+
//No lockfiles, nag nag nag!
|
| 82 |
+
add_action( 'admin_notices', array( &$this, 'lockfile_warning' ) );
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
function admin_footer(){
|
| 88 |
+
?>
|
| 89 |
+
<!-- wsblc admin footer -->
|
| 90 |
+
<div id='wsblc_updater_div'></div>
|
| 91 |
+
<script type='text/javascript'>
|
| 92 |
+
(function($){
|
| 93 |
+
|
| 94 |
+
function blcDoWork(){
|
| 95 |
+
$.post(
|
| 96 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 97 |
+
{
|
| 98 |
+
'action' : 'blc_work'
|
| 99 |
+
},
|
| 100 |
+
function (data, textStatus){
|
| 101 |
+
|
| 102 |
+
}
|
| 103 |
+
);
|
| 104 |
+
}
|
| 105 |
+
//Call it the first time
|
| 106 |
+
blcDoWork();
|
| 107 |
+
|
| 108 |
+
//Then call it periodically every X seconds
|
| 109 |
+
setInterval(blcDoWork, <?php echo (intval($this->conf->options['max_execution_time']) + 1 )*1000; ?>);
|
| 110 |
+
|
| 111 |
+
})(jQuery);
|
| 112 |
+
</script>
|
| 113 |
+
<!-- /wsblc admin footer -->
|
| 114 |
+
<?php
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
function is_excluded($url){
|
| 118 |
+
if (!is_array($this->conf->options['exclusion_list'])) return false;
|
| 119 |
+
foreach($this->conf->options['exclusion_list'] as $excluded_word){
|
| 120 |
+
if (stristr($url, $excluded_word)){
|
| 121 |
+
return true;
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
return false;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
function dashboard_widget(){
|
| 128 |
+
?>
|
| 129 |
+
<p id='wsblc_activity_box'>Loading...</p>
|
| 130 |
+
<script type='text/javascript'>
|
| 131 |
+
jQuery(function($){
|
| 132 |
+
var blc_was_autoexpanded = false;
|
| 133 |
+
|
| 134 |
+
function blcDashboardStatus(){
|
| 135 |
+
$.getJSON(
|
| 136 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 137 |
+
{
|
| 138 |
+
'action' : 'blc_dashboard_status'
|
| 139 |
+
},
|
| 140 |
+
function (data, textStatus){
|
| 141 |
+
if ( data && ( typeof(data.text) != 'undefined' ) ) {
|
| 142 |
+
$('#wsblc_activity_box').html(data.text);
|
| 143 |
+
<?php if ( $this->conf->options['autoexpand_widget'] ) { ?>
|
| 144 |
+
//Expand the widget if there are broken links.
|
| 145 |
+
//Do this only once per pageload so as not to annoy the user.
|
| 146 |
+
if ( !blc_was_autoexpanded && ( data.status.broken_links > 0 ) ){
|
| 147 |
+
$('#blc_dashboard_widget.postbox').removeClass('closed');
|
| 148 |
+
blc_was_autoexpanded = true;
|
| 149 |
+
};
|
| 150 |
+
<?php } ?>
|
| 151 |
+
} else {
|
| 152 |
+
$('#wsblc_activity_box').html('[ Network error ]');
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
setTimeout( blcDashboardStatus, 120*1000 ); //...update every two minutes
|
| 156 |
+
}
|
| 157 |
+
);
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
blcDashboardStatus();//Call it the first time
|
| 161 |
+
|
| 162 |
+
});
|
| 163 |
+
</script>
|
| 164 |
+
<?php
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
function dashboard_widget_control( $widget_id, $form_inputs = array() ){
|
| 168 |
+
if ( 'POST' == $_SERVER['REQUEST_METHOD'] && 'blc_dashboard_widget' == $_POST['widget_id'] ) {
|
| 169 |
+
//It appears $form_inputs isn't used in the current WP version, so lets just use $_POST
|
| 170 |
+
$this->conf->options['autoexpand_widget'] = !empty($_POST['blc-autoexpand']);
|
| 171 |
+
$this->conf->save_options();
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
?>
|
| 175 |
+
<p><label for="blc-autoexpand">
|
| 176 |
+
<input id="blc-autoexpand" name="blc-autoexpand" type="checkbox" value="1" <?php if ( $this->conf->options['autoexpand_widget'] ) echo 'checked="checked"'; ?> />
|
| 177 |
+
Automatically expand the widget if broken links have been detected
|
| 178 |
+
</label></p>
|
| 179 |
+
<?php
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
function admin_print_scripts(){
|
| 183 |
+
//jQuery is used for AJAX and effects
|
| 184 |
+
wp_enqueue_script('jquery');
|
| 185 |
+
wp_enqueue_script('jquery-ui-core');
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
/**
|
| 189 |
+
* ws_broken_link_checker::post_deleted()
|
| 190 |
+
* A hook for post_deleted. Remove link instances associated with that post.
|
| 191 |
+
*
|
| 192 |
+
* @param int $post_id
|
| 193 |
+
* @return void
|
| 194 |
+
*/
|
| 195 |
+
function post_deleted($post_id){
|
| 196 |
+
global $wpdb;
|
| 197 |
+
|
| 198 |
+
//FB::log($post_id, "Post deleted");
|
| 199 |
+
//Remove this post's instances
|
| 200 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 201 |
+
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
| 202 |
+
$q = $wpdb->prepare($q, intval($post_id) );
|
| 203 |
+
|
| 204 |
+
//FB::log($q, 'Executing query');
|
| 205 |
+
|
| 206 |
+
if ( $wpdb->query( $q ) === false ){
|
| 207 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
//Remove the synch record
|
| 211 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_synch
|
| 212 |
+
WHERE source_id = %d AND source_type = 'post'";
|
| 213 |
+
$wpdb->query( $wpdb->prepare($q, intval($post_id)) );
|
| 214 |
+
|
| 215 |
+
//Remove any dangling link records
|
| 216 |
+
$this->cleanup_links();
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
function post_saved($post_id){
|
| 220 |
+
global $wpdb;
|
| 221 |
+
|
| 222 |
+
$post = get_post($post_id);
|
| 223 |
+
//Only check links in posts, not revisions and attachments
|
| 224 |
+
if ( ($post->post_type != 'post') && ($post->post_type != 'page') ) return null;
|
| 225 |
+
//Only check published posts
|
| 226 |
+
if ( $post->post_status != 'publish' ) return null;
|
| 227 |
+
|
| 228 |
+
$this->mark_unsynched( $post_id, 'post' );
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
function initiate_recheck(){
|
| 232 |
+
global $wpdb;
|
| 233 |
+
|
| 234 |
+
//Delete all discovered instances
|
| 235 |
+
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_instances");
|
| 236 |
+
|
| 237 |
+
//Delete all discovered links
|
| 238 |
+
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_links");
|
| 239 |
+
|
| 240 |
+
//Mark all posts, custom fields and bookmarks for processing.
|
| 241 |
+
$this->resynch();
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
function resynch(){
|
| 245 |
+
global $wpdb;
|
| 246 |
+
|
| 247 |
+
//Drop all synchronization records
|
| 248 |
+
$wpdb->query("TRUNCATE {$wpdb->prefix}blc_synch");
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
//Create new synchronization records for posts
|
| 252 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
| 253 |
+
SELECT id, 'post', 0
|
| 254 |
+
FROM {$wpdb->posts}
|
| 255 |
+
WHERE
|
| 256 |
+
{$wpdb->posts}.post_status = 'publish'
|
| 257 |
+
AND {$wpdb->posts}.post_type IN ('post', 'page')";
|
| 258 |
+
$wpdb->query( $q );
|
| 259 |
+
|
| 260 |
+
//Create new synchronization records for bookmarks (the blogroll)
|
| 261 |
+
$q = "INSERT INTO {$wpdb->prefix}blc_synch(source_id, source_type, synched)
|
| 262 |
+
SELECT link_id, 'blogroll', 0
|
| 263 |
+
FROM {$wpdb->links}
|
| 264 |
+
WHERE 1";
|
| 265 |
+
$wpdb->query( $q );
|
| 266 |
+
|
| 267 |
+
//Delete invalid instances
|
| 268 |
+
$this->cleanup_instances();
|
| 269 |
+
//Delete orphaned links
|
| 270 |
+
$this->cleanup_links();
|
| 271 |
+
|
| 272 |
+
$this->conf->options['need_resynch'] = true;
|
| 273 |
+
$this->conf->save_options();
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
function mark_unsynched( $source_id, $source_type ){
|
| 277 |
+
global $wpdb;
|
| 278 |
+
|
| 279 |
+
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
| 280 |
+
VALUES( %d, %s, %d, NOW() )";
|
| 281 |
+
$rez = $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 0 ) );
|
| 282 |
+
|
| 283 |
+
if ( !$this->conf->options['need_resynch'] ){
|
| 284 |
+
$this->conf->options['need_resynch'] = true;
|
| 285 |
+
$this->conf->save_options();
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
return $rez;
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
function mark_synched( $source_id, $source_type ){
|
| 292 |
+
global $wpdb;
|
| 293 |
+
//FB::log("Marking $source_type $source_id as synched.");
|
| 294 |
+
$q = "REPLACE INTO {$wpdb->prefix}blc_synch( source_id, source_type, synched, last_synch)
|
| 295 |
+
VALUES( %d, %s, %d, NOW() )";
|
| 296 |
+
return $wpdb->query( $wpdb->prepare( $q, $source_id, $source_type, 1 ) );
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
function activation(){
|
| 300 |
+
//Prepare the database.
|
| 301 |
+
$this->upgrade_database();
|
| 302 |
+
|
| 303 |
+
//Clear the instance table and mark all posts and other parse-able objects as unsynchronized.
|
| 304 |
+
$this->resynch();
|
| 305 |
+
|
| 306 |
+
//Save the default options.
|
| 307 |
+
$this->conf->save_options();
|
| 308 |
+
|
| 309 |
+
//And optimize my DB tables, too (for good measure)
|
| 310 |
+
$this->optimize_database();
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
/**
|
| 314 |
+
* ws_broken_link_checker::upgrade_database()
|
| 315 |
+
* Create and/or upgrade database tables
|
| 316 |
+
*
|
| 317 |
+
* @return void
|
| 318 |
+
*/
|
| 319 |
+
function upgrade_database(){
|
| 320 |
+
global $wpdb;
|
| 321 |
+
|
| 322 |
+
//Do we need to upgrade?
|
| 323 |
+
//[ Disabled for now, was causing issues when the user manually deletes the plugin ]
|
| 324 |
+
//if ( $this->db_version == $this->conf->options['current_db_version'] ) return;
|
| 325 |
+
|
| 326 |
+
//Delete tables used by older versions of the plugin
|
| 327 |
+
$rez = $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}blc_linkdata, {$wpdb->prefix}blc_postdata" );
|
| 328 |
+
if ( $rez === false ){
|
| 329 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 330 |
+
return false;
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
require_once (ABSPATH . 'wp-admin/includes/upgrade.php');
|
| 334 |
+
|
| 335 |
+
//Create the link table if it doesn't exist yet.
|
| 336 |
+
$q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_links (
|
| 337 |
+
link_id int(20) unsigned NOT NULL auto_increment,
|
| 338 |
+
url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 339 |
+
last_check datetime NOT NULL default '0000-00-00 00:00:00',
|
| 340 |
+
check_count int(2) unsigned NOT NULL default '0',
|
| 341 |
+
final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 342 |
+
redirect_count smallint(5) unsigned NOT NULL,
|
| 343 |
+
log text NOT NULL,
|
| 344 |
+
http_code smallint(6) NOT NULL,
|
| 345 |
+
request_duration float NOT NULL default '0',
|
| 346 |
+
timeout tinyint(1) unsigned NOT NULL default '0',
|
| 347 |
+
|
| 348 |
+
PRIMARY KEY (link_id),
|
| 349 |
+
KEY url (url(150)),
|
| 350 |
+
KEY final_url (final_url(150)),
|
| 351 |
+
KEY http_code (http_code),
|
| 352 |
+
KEY timeout (timeout)
|
| 353 |
+
)";
|
| 354 |
+
if ( $wpdb->query( $q ) === false ){
|
| 355 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 356 |
+
return false;
|
| 357 |
+
};
|
| 358 |
+
|
| 359 |
+
//Fix URL fields so that they are collated as case-sensitive (this can't be done via dbDelta)
|
| 360 |
+
$q = "ALTER TABLE {$wpdb->prefix}blc_links
|
| 361 |
+
MODIFY url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
|
| 362 |
+
MODIFY final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL";
|
| 363 |
+
if ( $wpdb->query( $q ) === false ){
|
| 364 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 365 |
+
return false;
|
| 366 |
+
};
|
| 367 |
+
|
| 368 |
+
//Create the instance table if it doesn't exist yet.
|
| 369 |
+
$q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_instances (
|
| 370 |
+
instance_id int(10) unsigned NOT NULL auto_increment,
|
| 371 |
+
link_id int(10) unsigned NOT NULL,
|
| 372 |
+
source_id int(10) unsigned NOT NULL,
|
| 373 |
+
source_type enum('post','blogroll','custom_field') NOT NULL default 'post',
|
| 374 |
+
link_text varchar(250) NOT NULL,
|
| 375 |
+
instance_type enum('link','image') NOT NULL default 'link',
|
| 376 |
+
|
| 377 |
+
PRIMARY KEY (instance_id),
|
| 378 |
+
KEY link_id (link_id),
|
| 379 |
+
KEY source_id (source_id,source_type)
|
| 380 |
+
)";
|
| 381 |
+
if ( $wpdb->query( $q ) === false ){
|
| 382 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 383 |
+
return false;
|
| 384 |
+
};
|
| 385 |
+
|
| 386 |
+
//....
|
| 387 |
+
$q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_synch (
|
| 388 |
+
source_id int(20) unsigned NOT NULL,
|
| 389 |
+
source_type enum('post','blogroll') NOT NULL,
|
| 390 |
+
synched tinyint(3) unsigned NOT NULL,
|
| 391 |
+
last_synch datetime NOT NULL,
|
| 392 |
+
PRIMARY KEY (source_id, source_type),
|
| 393 |
+
KEY synched (synched)
|
| 394 |
+
)";
|
| 395 |
+
if ( $wpdb->query( $q ) === false ){
|
| 396 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 397 |
+
return false;
|
| 398 |
+
};
|
| 399 |
+
|
| 400 |
+
$this->conf->options['current_db_version'] = $this->db_version;
|
| 401 |
+
$this->conf->save_options();
|
| 402 |
+
|
| 403 |
+
return true;
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
/**
|
| 407 |
+
* wsBrokenLinkChecker::optimize_database()
|
| 408 |
+
* Optimize the plugin's tables
|
| 409 |
+
*
|
| 410 |
+
* @return void
|
| 411 |
+
*/
|
| 412 |
+
function optimize_database(){
|
| 413 |
+
global $wpdb;
|
| 414 |
+
|
| 415 |
+
$wpdb->query("OPTIMIZE TABLE {$wpdb->prefix}blc_links, {$wpdb->prefix}blc_instances, {$wpdb->prefix}blc_synch");
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
function admin_menu(){
|
| 419 |
+
add_options_page('Link Checker Settings', 'Link Checker', 'manage_options',
|
| 420 |
+
'link-checker-settings',array(&$this, 'options_page'));
|
| 421 |
+
if (current_user_can('manage_options'))
|
| 422 |
+
add_filter('plugin_action_links', array(&$this, 'plugin_action_links'), 10, 2);
|
| 423 |
+
|
| 424 |
+
add_management_page('View Broken Links', 'Broken Links', 'edit_others_posts',
|
| 425 |
+
'view-broken-links',array(&$this, 'links_page'));
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
/**
|
| 429 |
+
* plugin_action_links()
|
| 430 |
+
* Handler for the 'plugin_action_links' hook. Adds a "Settings" link to this plugin's entry
|
| 431 |
+
* on the plugin list.
|
| 432 |
+
*
|
| 433 |
+
* @param array $links
|
| 434 |
+
* @param string $file
|
| 435 |
+
* @return array
|
| 436 |
+
*/
|
| 437 |
+
function plugin_action_links($links, $file) {
|
| 438 |
+
if ($file == $this->my_basename)
|
| 439 |
+
$links[] = "<a href='options-general.php?page=link-checker-settings'>" . __('Settings') . "</a>";
|
| 440 |
+
return $links;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
function mytruncate($str, $max_length=50){
|
| 444 |
+
if(strlen($str)<=$max_length) return $str;
|
| 445 |
+
return (substr($str, 0, $max_length-3).'...');
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
function options_page(){
|
| 449 |
+
if (isset($_GET['recheck']) && ($_GET['recheck'] == 'true')) {
|
| 450 |
+
$this->initiate_recheck();
|
| 451 |
+
}
|
| 452 |
+
if (isset($_GET['updated']) && ($_GET['updated'] == 'true')) {
|
| 453 |
+
if(isset($_POST['submit'])) {
|
| 454 |
+
check_admin_referer('link-checker-options');
|
| 455 |
+
|
| 456 |
+
$new_execution_time = intval($_POST['max_execution_time']);
|
| 457 |
+
if( $new_execution_time > 0 ){
|
| 458 |
+
$this->conf->options['max_execution_time'] = $new_execution_time;
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
$new_check_threshold=intval($_POST['check_threshold']);
|
| 462 |
+
if( $new_check_threshold > 0 ){
|
| 463 |
+
$this->conf->options['check_threshold'] = $new_check_threshold;
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
$this->conf->options['mark_broken_links'] = !empty($_POST['mark_broken_links']);
|
| 467 |
+
$new_broken_link_css = trim($_POST['broken_link_css']);
|
| 468 |
+
$this->conf->options['broken_link_css'] = $new_broken_link_css;
|
| 469 |
+
|
| 470 |
+
$this->conf->options['exclusion_list']=array_filter( preg_split( '/[\s\r\n]+/',
|
| 471 |
+
$_POST['exclusion_list'], -1, PREG_SPLIT_NO_EMPTY ) );
|
| 472 |
+
//TODO: Maybe update affected links when exclusion list changes (expensive).
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
$new_custom_fields = array_filter( preg_split( '/[\s\r\n]+/',
|
| 476 |
+
$_POST['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY ) );
|
| 477 |
+
$diff1 = array_diff( $new_custom_fields, $this->conf->options['custom_fields'] );
|
| 478 |
+
$diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields );
|
| 479 |
+
$this->conf->options['custom_fields'] = $new_custom_fields;
|
| 480 |
+
|
| 481 |
+
$this->conf->save_options();
|
| 482 |
+
|
| 483 |
+
/*
|
| 484 |
+
If the list of custom fields was modified then we MUST resynchronize or
|
| 485 |
+
custom fields linked with existing posts may not be detected. This is somewhat
|
| 486 |
+
inefficient.
|
| 487 |
+
*/
|
| 488 |
+
if ( ( count($diff1) > 0 ) || ( count($diff2) > 0 ) ){
|
| 489 |
+
$this->resynch();
|
| 490 |
+
}
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
}
|
| 494 |
+
|
| 495 |
+
?>
|
| 496 |
+
<div class="wrap"><h2>Broken Link Checker Options</h2>
|
| 497 |
+
|
| 498 |
+
<form name="link_checker_options" method="post" action="<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&updated=true">
|
| 499 |
+
<?php
|
| 500 |
+
wp_nonce_field('link-checker-options');
|
| 501 |
+
?>
|
| 502 |
+
|
| 503 |
+
<table class="form-table">
|
| 504 |
+
|
| 505 |
+
<tr valign="top">
|
| 506 |
+
<th scope="row">Status</th>
|
| 507 |
+
<td>
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
<div id='wsblc_full_status'>
|
| 511 |
+
<br/><br/><br/>
|
| 512 |
+
</div>
|
| 513 |
+
<script type='text/javascript'>
|
| 514 |
+
(function($){
|
| 515 |
+
|
| 516 |
+
function blcUpdateStatus(){
|
| 517 |
+
$.getJSON(
|
| 518 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 519 |
+
{
|
| 520 |
+
'action' : 'blc_full_status'
|
| 521 |
+
},
|
| 522 |
+
function (data, textStatus){
|
| 523 |
+
if ( data && ( typeof(data['text']) != 'undefined' ) ){
|
| 524 |
+
$('#wsblc_full_status').html(data.text);
|
| 525 |
+
} else {
|
| 526 |
+
$('#wsblc_full_status').html('[ Network error ]');
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
setTimeout(blcUpdateStatus, 10000); //...update every 10 seconds
|
| 530 |
+
}
|
| 531 |
+
);
|
| 532 |
+
}
|
| 533 |
+
blcUpdateStatus();//Call it the first time
|
| 534 |
+
|
| 535 |
+
})(jQuery);
|
| 536 |
+
</script>
|
| 537 |
+
<?php //JHS: Recheck all posts link: ?>
|
| 538 |
+
<p><input class="button" type="button" name="recheckbutton" value="Re-check all pages" onclick="location.replace('<?php echo basename($_SERVER['PHP_SELF']); ?>?page=link-checker-settings&recheck=true')" /></p>
|
| 539 |
+
</td>
|
| 540 |
+
</tr>
|
| 541 |
+
|
| 542 |
+
<tr valign="top">
|
| 543 |
+
<th scope="row">Check each link</th>
|
| 544 |
+
<td>
|
| 545 |
+
|
| 546 |
+
Every <input type="text" name="check_threshold" id="check_threshold"
|
| 547 |
+
value="<?php echo $this->conf->options['check_threshold']; ?>" size='5' maxlength='3'/>
|
| 548 |
+
hours
|
| 549 |
+
<br/>
|
| 550 |
+
<span class="description">
|
| 551 |
+
Existing links will be checked this often. New links will usually be checked ASAP.
|
| 552 |
+
</span>
|
| 553 |
+
|
| 554 |
+
</td>
|
| 555 |
+
</tr>
|
| 556 |
+
|
| 557 |
+
<tr valign="top">
|
| 558 |
+
<th scope="row">Broken link CSS</th>
|
| 559 |
+
<td>
|
| 560 |
+
<input type="checkbox" name="mark_broken_links" id="mark_broken_links"
|
| 561 |
+
<?php if ($this->conf->options['mark_broken_links']) echo ' checked="checked"'; ?>/>
|
| 562 |
+
<label for='mark_broken_links'>Apply <em>class="broken_link"</em> to broken links</label><br/>
|
| 563 |
+
<textarea name="broken_link_css" id="broken_link_css" cols='45' rows='4'/><?php
|
| 564 |
+
if( isset($this->conf->options['broken_link_css']) )
|
| 565 |
+
echo $this->conf->options['broken_link_css'];
|
| 566 |
+
?></textarea>
|
| 567 |
+
|
| 568 |
+
</td>
|
| 569 |
+
</tr>
|
| 570 |
+
|
| 571 |
+
<tr valign="top">
|
| 572 |
+
<th scope="row">Exclusion list</th>
|
| 573 |
+
<td>Don't check links where the URL contains any of these words (one per line) :<br/>
|
| 574 |
+
<textarea name="exclusion_list" id="exclusion_list" cols='45' rows='4' wrap='off'/><?php
|
| 575 |
+
if( isset($this->conf->options['exclusion_list']) )
|
| 576 |
+
echo implode("\n", $this->conf->options['exclusion_list']);
|
| 577 |
+
?></textarea>
|
| 578 |
+
|
| 579 |
+
</td>
|
| 580 |
+
</tr>
|
| 581 |
+
|
| 582 |
+
<tr valign="top">
|
| 583 |
+
<th scope="row">Custom fields</th>
|
| 584 |
+
<td>Check URLs entered in these custom fields (one per line) : <br/>
|
| 585 |
+
<textarea name="blc_custom_fields" id="blc_custom_fields" cols='45' rows='4' /><?php
|
| 586 |
+
if( isset($this->conf->options['custom_fields']) )
|
| 587 |
+
echo implode("\n", $this->conf->options['custom_fields']);
|
| 588 |
+
?></textarea>
|
| 589 |
+
|
| 590 |
+
</td>
|
| 591 |
+
</tr>
|
| 592 |
+
|
| 593 |
+
<tr valign="top">
|
| 594 |
+
<th scope="row">Max. execution time (advanced)</th>
|
| 595 |
+
<td>
|
| 596 |
+
|
| 597 |
+
<input type="text" name="max_execution_time" id="max_execution_time"
|
| 598 |
+
value="<?php echo $this->conf->options['max_execution_time']; ?>" size='5' maxlength='3'/>
|
| 599 |
+
seconds
|
| 600 |
+
<br/><span class="description">
|
| 601 |
+
The plugin works by periodically creating a background worker instance that parses your posts looking for links,
|
| 602 |
+
checks the discovered URLs, and performs other time-consuming tasks. Here you can set for how long, at most,
|
| 603 |
+
the background instance may run each time before stopping.
|
| 604 |
+
</span>
|
| 605 |
+
|
| 606 |
+
</td>
|
| 607 |
+
</tr>
|
| 608 |
+
|
| 609 |
+
</table>
|
| 610 |
+
|
| 611 |
+
<p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
|
| 612 |
+
</form>
|
| 613 |
+
</div>
|
| 614 |
+
<?php
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
function links_page(){
|
| 618 |
+
global $wpdb;
|
| 619 |
+
|
| 620 |
+
//Available filters by link type + the appropriate WHERE expressions
|
| 621 |
+
$filters = array(
|
| 622 |
+
'broken' => array(
|
| 623 |
+
'where_expr' => '( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( check_count > 0 ) AND ( http_code <> ' . BLC_CHECKING . ')',
|
| 624 |
+
'name' => 'Broken',
|
| 625 |
+
'heading' => 'Broken Links',
|
| 626 |
+
'heading_zero' => 'No broken links found'
|
| 627 |
+
),
|
| 628 |
+
'redirects' => array(
|
| 629 |
+
'where_expr' => '( redirect_count > 0 )',
|
| 630 |
+
'name' => 'Redirects',
|
| 631 |
+
'heading' => 'Redirected Links',
|
| 632 |
+
'heading_zero' => 'No redirects found'
|
| 633 |
+
),
|
| 634 |
+
|
| 635 |
+
'all' => array(
|
| 636 |
+
'where_expr' => '1',
|
| 637 |
+
'name' => 'All',
|
| 638 |
+
'heading' => 'Detected Links',
|
| 639 |
+
'heading_zero' => 'No links found (yet)'
|
| 640 |
+
),
|
| 641 |
+
);
|
| 642 |
+
|
| 643 |
+
$link_type = isset($_GET['link_type'])?$_GET['link_type']:'broken';
|
| 644 |
+
if ( !isset($filters[$link_type]) ){
|
| 645 |
+
$link_type = 'broken';
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
+
//Get the desired page number (must be > 0)
|
| 649 |
+
$page = isset($_GET['paged'])?intval($_GET['paged']):'1';
|
| 650 |
+
if ($page < 1) $page = 1;
|
| 651 |
+
|
| 652 |
+
//Links per page [1 - 200]
|
| 653 |
+
$per_page = isset($_GET['per_page'])?intval($_GET['per_page']):'30';
|
| 654 |
+
if ($per_page < 1){
|
| 655 |
+
$per_page = 30;
|
| 656 |
+
} else if ($per_page > 200){
|
| 657 |
+
$per_page = 200;
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
//calculate the number of various links
|
| 661 |
+
foreach ($filters as $filter => $data){
|
| 662 |
+
$filters[$filter]['count'] = $wpdb->get_var(
|
| 663 |
+
"SELECT COUNT(*) FROM {$wpdb->prefix}blc_links WHERE ".$data['where_expr'] );
|
| 664 |
+
}
|
| 665 |
+
$current_filter = $filters[$link_type];
|
| 666 |
+
$max_pages = ceil($current_filter['count'] / $per_page);
|
| 667 |
+
|
| 668 |
+
|
| 669 |
+
//Select the required links + 1 instance per link.
|
| 670 |
+
//Note : The query might be somewhat inefficient, but I can't think of any better way to do this.
|
| 671 |
+
$q = "SELECT
|
| 672 |
+
links.*,
|
| 673 |
+
instances.instance_id, instances.source_id, instances.source_type,
|
| 674 |
+
instances.link_text, instances.instance_type,
|
| 675 |
+
COUNT(*) as instance_count,
|
| 676 |
+
posts.post_title,
|
| 677 |
+
posts.post_date
|
| 678 |
+
|
| 679 |
+
FROM
|
| 680 |
+
{$wpdb->prefix}blc_links AS links,
|
| 681 |
+
{$wpdb->prefix}blc_instances as instances LEFT JOIN {$wpdb->posts} as posts ON instances.source_id = posts.ID
|
| 682 |
+
|
| 683 |
+
WHERE
|
| 684 |
+
links.link_id = instances.link_id
|
| 685 |
+
AND ". $current_filter['where_expr'] ."
|
| 686 |
+
|
| 687 |
+
GROUP BY links.link_id
|
| 688 |
+
LIMIT ".( ($page-1) * $per_page ).", $per_page";
|
| 689 |
+
//echo "<pre>$q</pre>";
|
| 690 |
+
|
| 691 |
+
$links = $wpdb->get_results($q, ARRAY_A);
|
| 692 |
+
if ($links){
|
| 693 |
+
/*
|
| 694 |
+
echo '<pre>';
|
| 695 |
+
print_r($links);
|
| 696 |
+
echo '</pre>';
|
| 697 |
+
//*/
|
| 698 |
+
} else {
|
| 699 |
+
echo $wpdb->last_error;
|
| 700 |
+
}
|
| 701 |
+
?>
|
| 702 |
+
|
| 703 |
+
<script type='text/javascript'>
|
| 704 |
+
var blc_current_filter = '<?php echo $link_type; ?>';
|
| 705 |
+
</script>
|
| 706 |
+
|
| 707 |
+
<style type='text/css'>
|
| 708 |
+
.blc-link-editor {
|
| 709 |
+
font-size: 1em;
|
| 710 |
+
width: 95%;
|
| 711 |
+
}
|
| 712 |
+
|
| 713 |
+
.blc-excluded-link {
|
| 714 |
+
background-color: #E2E2E2;
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
.blc-small-image {
|
| 718 |
+
display : block;
|
| 719 |
+
float: left;
|
| 720 |
+
padding-top: 2px;
|
| 721 |
+
margin-right: 3px;
|
| 722 |
+
}
|
| 723 |
+
</style>
|
| 724 |
+
|
| 725 |
+
<div class="wrap">
|
| 726 |
+
<h2><?php
|
| 727 |
+
//Output a header matching the current filter
|
| 728 |
+
if ( $current_filter['count'] > 0 ){
|
| 729 |
+
echo "<span class='current-link-count'>{$current_filter[count]}</span> " . $current_filter['heading'];
|
| 730 |
+
} else {
|
| 731 |
+
echo "<span class='current-link-count'></span>" . $current_filter['heading_zero'];
|
| 732 |
+
}
|
| 733 |
+
?></h2>
|
| 734 |
+
|
| 735 |
+
<div class='tablenav'>
|
| 736 |
+
<ul class="subsubsub">
|
| 737 |
+
<?php
|
| 738 |
+
//Construct a submenu of filter types
|
| 739 |
+
$items = array();
|
| 740 |
+
foreach ($filters as $filter => $data){
|
| 741 |
+
$class = $number_class = '';
|
| 742 |
+
|
| 743 |
+
if ( $link_type == $filter ) $class = 'class="current"';
|
| 744 |
+
if ( $link_type == $filter ) $number_class = 'current-link-count';
|
| 745 |
+
|
| 746 |
+
$items[] = "<li><a href='tools.php?page=view-broken-links&link_type=$filter' $class>
|
| 747 |
+
{$data[name]}</a> <span class='count'>(<span class='$number_class'>{$data[count]}</span>)</span>";
|
| 748 |
+
}
|
| 749 |
+
echo implode(' |</li>', $items);
|
| 750 |
+
unset($items);
|
| 751 |
+
?>
|
| 752 |
+
</ul>
|
| 753 |
+
<?php
|
| 754 |
+
//Display pagination links
|
| 755 |
+
$page_links = paginate_links( array(
|
| 756 |
+
'base' => add_query_arg( 'paged', '%#%' ),
|
| 757 |
+
'format' => '',
|
| 758 |
+
'prev_text' => __('«'),
|
| 759 |
+
'next_text' => __('»'),
|
| 760 |
+
'total' => $max_pages,
|
| 761 |
+
'current' => $page
|
| 762 |
+
));
|
| 763 |
+
|
| 764 |
+
if ( $page_links ) {
|
| 765 |
+
echo '<div class="tablenav-pages">';
|
| 766 |
+
$page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>' ) . '</span>%s',
|
| 767 |
+
number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
|
| 768 |
+
number_format_i18n( min( $page * $per_page, count($links) ) ),
|
| 769 |
+
number_format_i18n( $current_filter['count'] ),
|
| 770 |
+
$page_links
|
| 771 |
+
);
|
| 772 |
+
echo $page_links_text;
|
| 773 |
+
echo '</div>';
|
| 774 |
+
}
|
| 775 |
+
?>
|
| 776 |
+
|
| 777 |
+
</div>
|
| 778 |
+
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
<?php
|
| 782 |
+
if($links && (count($links)>0)){
|
| 783 |
+
?>
|
| 784 |
+
<table class="widefat">
|
| 785 |
+
<thead>
|
| 786 |
+
<tr>
|
| 787 |
+
|
| 788 |
+
<th scope="col">Source
|
| 789 |
+
</th>
|
| 790 |
+
<th scope="col">Link Text</th>
|
| 791 |
+
<th scope="col">URL</th>
|
| 792 |
+
|
| 793 |
+
<?php if ( 'broken' == $link_type ) { ?>
|
| 794 |
+
<th scope="col"> </th>
|
| 795 |
+
<?php } ?>
|
| 796 |
+
|
| 797 |
+
</tr>
|
| 798 |
+
</thead>
|
| 799 |
+
<tbody id="the-list">
|
| 800 |
+
<?php
|
| 801 |
+
$rowclass = ''; $rownum = 0;
|
| 802 |
+
foreach ($links as $link) {
|
| 803 |
+
$rownum++;
|
| 804 |
+
|
| 805 |
+
$rowclass = 'alternate' == $rowclass ? '' : 'alternate';
|
| 806 |
+
$excluded = $this->is_excluded( $link['url'] );
|
| 807 |
+
if ( $excluded ) $rowclass .= ' blc-excluded-link';
|
| 808 |
+
|
| 809 |
+
?>
|
| 810 |
+
<tr id='<?php echo "blc-row-$rownum"; ?>' class='blc-row <?php echo $rowclass; ?>'>
|
| 811 |
+
<td class='post-title column-title'>
|
| 812 |
+
<span class='blc-link-id' style='display:none;'><?php echo $link['link_id']; ?></span>
|
| 813 |
+
<?php
|
| 814 |
+
if ( ('post' == $link['source_type']) || ('custom_field' == $link['source_type']) ){
|
| 815 |
+
|
| 816 |
+
echo "<a class='row-title' href='post.php?action=edit&post=$link[source_id]' title='Edit this post'>{$link[post_title]}</a>";
|
| 817 |
+
|
| 818 |
+
//Output inline action links (copied from edit-post-rows.php)
|
| 819 |
+
$actions = array();
|
| 820 |
+
if ( current_user_can('edit_post', $link['source_id']) ) {
|
| 821 |
+
$actions['edit'] = '<span class="edit"><a href="' . get_edit_post_link($link['source_id'], true) . '" title="' . attribute_escape(__('Edit this post')) . '">' . __('Edit') . '</a>';
|
| 822 |
+
$actions['delete'] = "<span class='delete'><a class='submitdelete' title='" . attribute_escape(__('Delete this post')) . "' href='" . wp_nonce_url("post.php?action=delete&post=".$link['source_id'], 'delete-post_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete the post '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['post_title'] )) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
| 823 |
+
}
|
| 824 |
+
$actions['view'] = '<span class="view"><a href="' . get_permalink($link['source_id']) . '" title="' . attribute_escape(sprintf(__('View "%s"'), $link['post_title'])) . '" rel="permalink">' . __('View') . '</a>';
|
| 825 |
+
echo '<div class="row-actions">';
|
| 826 |
+
echo implode(' | </span>', $actions);
|
| 827 |
+
echo '</div>';
|
| 828 |
+
|
| 829 |
+
} elseif ( 'blogroll' == $link['source_type'] ) {
|
| 830 |
+
|
| 831 |
+
echo "<a class='row-title' href='link.php?action=edit&link_id=$link[source_id]' title='Edit this bookmark'>{$link[link_text]}</a>";
|
| 832 |
+
|
| 833 |
+
//Output inline action links
|
| 834 |
+
$actions = array();
|
| 835 |
+
if ( current_user_can('manage_links') ) {
|
| 836 |
+
$actions['edit'] = '<span class="edit"><a href="link.php?action=edit&link_id=' . $link['source_id'] . '" title="' . attribute_escape(__('Edit this bookmark')) . '">' . __('Edit') . '</a>';
|
| 837 |
+
$actions['delete'] = "<span class='delete'><a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&link_id={$link[source_id]}", 'delete-bookmark_' . $link['source_id']) . "' onclick=\"if ( confirm('" . js_escape(sprintf( __("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $link['link_text'])) . "') ) { return true;}return false;\">" . __('Delete') . "</a>";
|
| 838 |
+
}
|
| 839 |
+
|
| 840 |
+
echo '<div class="row-actions">';
|
| 841 |
+
echo implode(' | </span>', $actions);
|
| 842 |
+
echo '</div>';
|
| 843 |
+
|
| 844 |
+
} elseif ( empty($link['source_type']) ){
|
| 845 |
+
|
| 846 |
+
echo "[An orphaned link! This is a bug.]";
|
| 847 |
+
|
| 848 |
+
}
|
| 849 |
+
?>
|
| 850 |
+
</td>
|
| 851 |
+
<td class='blc-link-text'><?php
|
| 852 |
+
if ( 'post' == $link['source_type'] ){
|
| 853 |
+
|
| 854 |
+
if ( 'link' == $link['instance_type'] ) {
|
| 855 |
+
print strip_tags($link['link_text']);
|
| 856 |
+
} elseif ( 'image' == $link['instance_type'] ){
|
| 857 |
+
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/image.png' class='blc-small-image' alt='Image' title='Image'> Image";
|
| 858 |
+
} else {
|
| 859 |
+
echo '[ ??? ]';
|
| 860 |
+
}
|
| 861 |
+
|
| 862 |
+
} elseif ( 'custom_field' == $link['source_type'] ){
|
| 863 |
+
|
| 864 |
+
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/script_code.png' class='blc-small-image' title='Custom field' alt='Custom field'> ";
|
| 865 |
+
echo "<code>".$link['link_text']."</code>";
|
| 866 |
+
|
| 867 |
+
} elseif ( 'blogroll' == $link['source_type'] ){
|
| 868 |
+
//echo $link['link_text'];
|
| 869 |
+
echo "<img src='" . WP_PLUGIN_URL . "/broken-link-checker/images/link.png' class='blc-small-image' title='Bookmark' alt='Bookmark'> Bookmark";
|
| 870 |
+
}
|
| 871 |
+
?>
|
| 872 |
+
</td>
|
| 873 |
+
<td class='column-url'>
|
| 874 |
+
<a href='<?php print $link['url']; ?>' target='_blank' class='blc-link-url'>
|
| 875 |
+
<?php print $this->mytruncate($link['url']); ?></a>
|
| 876 |
+
<input type='text' id='link-editor-<?php print $rownum; ?>'
|
| 877 |
+
value='<?php print attribute_escape($link['url']); ?>'
|
| 878 |
+
class='blc-link-editor' style='display:none' />
|
| 879 |
+
<?php
|
| 880 |
+
//Output inline action links for the link/URL
|
| 881 |
+
$actions = array();
|
| 882 |
+
|
| 883 |
+
$actions['details'] = "<span class='view'><a class='blc-details-button' href='javascript:void(0)' title='Show more info about this link'>Details</a>";
|
| 884 |
+
|
| 885 |
+
$actions['delete'] = "<span class='delete'><a class='submitdelete blc-unlink-button' title='Remove this link from all posts' ".
|
| 886 |
+
"id='unlink-button-$rownum' href='javascript:void(0);'>Unlink</a>";
|
| 887 |
+
|
| 888 |
+
if ( $excluded ){
|
| 889 |
+
$actions['exclude'] = "<span class='delete'>Excluded";
|
| 890 |
+
} else {
|
| 891 |
+
$actions['exclude'] = "<span class='delete'><a class='submitdelete blc-exclude-button' title='Add this URL to the exclusion list' ".
|
| 892 |
+
"id='exclude-button-$rownum' href='javascript:void(0);'>Exclude</a>";
|
| 893 |
+
}
|
| 894 |
+
|
| 895 |
+
$actions['edit'] = "<span class='edit'><a href='javascript:void(0)' class='blc-edit-button' title='Edit link URL'>Edit URL</a>";
|
| 896 |
+
|
| 897 |
+
echo '<div class="row-actions">';
|
| 898 |
+
echo implode(' | </span>', $actions);
|
| 899 |
+
|
| 900 |
+
echo "<span style='display:none' class='blc-cancel-button-container'> ",
|
| 901 |
+
"| <a href='javascript:void(0)' class='blc-cancel-button' title='Cancel URL editing'>Cancel</a></span>";
|
| 902 |
+
|
| 903 |
+
echo '</div>';
|
| 904 |
+
?>
|
| 905 |
+
</td>
|
| 906 |
+
<?php if ( 'broken' == $link_type ) { ?>
|
| 907 |
+
<td><a href='javascript:void(0);'
|
| 908 |
+
id='discard_button-<?php print $rownum; ?>'
|
| 909 |
+
class='blc-discard-button'
|
| 910 |
+
title='Remove this message and mark the link as valid'>Discard</a>
|
| 911 |
+
</td>
|
| 912 |
+
<?php } ?>
|
| 913 |
+
</tr>
|
| 914 |
+
<!-- Link details -->
|
| 915 |
+
<tr id='<?php print "link-details-$rownum"; ?>' style='display:none;' class='blc-link-details'>
|
| 916 |
+
<td colspan='4'><?php $this->link_details_row($link); ?></td>
|
| 917 |
+
</tr><?php
|
| 918 |
+
}
|
| 919 |
+
?></tbody></table><?php
|
| 920 |
+
|
| 921 |
+
//Also display pagination links at the bottom
|
| 922 |
+
if ( $page_links ) {
|
| 923 |
+
echo '<div class="tablenav"><div class="tablenav-pages">';
|
| 924 |
+
$page_links_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s–%s of <span class="current-link-count">%s</span>' ) . '</span>%s',
|
| 925 |
+
number_format_i18n( ( $page - 1 ) * $per_page + 1 ),
|
| 926 |
+
number_format_i18n( min( $page * $per_page, count($links) ) ),
|
| 927 |
+
number_format_i18n( $current_filter['count'] ),
|
| 928 |
+
$page_links
|
| 929 |
+
);
|
| 930 |
+
echo $page_links_text;
|
| 931 |
+
echo '</div></div>';
|
| 932 |
+
}
|
| 933 |
+
};
|
| 934 |
+
?>
|
| 935 |
+
<?php $this->links_page_js(); ?>
|
| 936 |
+
</div>
|
| 937 |
+
<?php
|
| 938 |
+
}
|
| 939 |
+
|
| 940 |
+
function links_page_js(){
|
| 941 |
+
?>
|
| 942 |
+
<script type='text/javascript'>
|
| 943 |
+
|
| 944 |
+
function alterLinkCounter(factor){
|
| 945 |
+
cnt = parseInt(jQuery('.current-link-count').eq(0).html());
|
| 946 |
+
cnt = cnt + factor;
|
| 947 |
+
jQuery('.current-link-count').html(cnt);
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
jQuery(function($){
|
| 951 |
+
|
| 952 |
+
//The discard button - manually mark the link as valid. The link will be checked again later.
|
| 953 |
+
$(".blc-discard-button").click(function () {
|
| 954 |
+
var me = this;
|
| 955 |
+
$(me).html('Wait...');
|
| 956 |
+
|
| 957 |
+
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 958 |
+
|
| 959 |
+
$.post(
|
| 960 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 961 |
+
{
|
| 962 |
+
'action' : 'blc_discard',
|
| 963 |
+
'link_id' : link_id
|
| 964 |
+
},
|
| 965 |
+
function (data, textStatus){
|
| 966 |
+
if (data == 'OK'){
|
| 967 |
+
var master = $(me).parents('.blc-row');
|
| 968 |
+
var details = master.next('.blc-link-details');
|
| 969 |
+
|
| 970 |
+
details.hide();
|
| 971 |
+
//Flash the main row green to indicate success, then hide it.
|
| 972 |
+
var oldColor = master.css('background-color');
|
| 973 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
| 974 |
+
master.hide();
|
| 975 |
+
});
|
| 976 |
+
|
| 977 |
+
alterLinkCounter(-1);
|
| 978 |
+
} else {
|
| 979 |
+
$(me).html('Discard');
|
| 980 |
+
alert(data);
|
| 981 |
+
}
|
| 982 |
+
}
|
| 983 |
+
);
|
| 984 |
+
});
|
| 985 |
+
|
| 986 |
+
//The details button - display/hide detailed info about a link
|
| 987 |
+
$(".blc-details-button, .blc-link-text").click(function () {
|
| 988 |
+
$(this).parents('.blc-row').next('.blc-link-details').toggle();
|
| 989 |
+
});
|
| 990 |
+
|
| 991 |
+
//The edit button - edit/save the link's URL
|
| 992 |
+
$(".blc-edit-button").click(function () {
|
| 993 |
+
var edit_button = $(this);
|
| 994 |
+
var master = $(edit_button).parents('.blc-row');
|
| 995 |
+
var editor = $(master).find('.blc-link-editor');
|
| 996 |
+
var url_el = $(master).find('.blc-link-url');
|
| 997 |
+
var cancel_button_container = $(master).find('.blc-cancel-button-container');
|
| 998 |
+
|
| 999 |
+
//Find the current/original URL
|
| 1000 |
+
var orig_url = url_el.attr('href');
|
| 1001 |
+
//Find the link ID
|
| 1002 |
+
var link_id = $(master).find('.blc-link-id').html();
|
| 1003 |
+
|
| 1004 |
+
if ( !$(editor).is(':visible') ){
|
| 1005 |
+
//Begin editing
|
| 1006 |
+
url_el.hide();
|
| 1007 |
+
editor.show();
|
| 1008 |
+
cancel_button_container.show();
|
| 1009 |
+
editor.focus();
|
| 1010 |
+
editor.select();
|
| 1011 |
+
edit_button.html('Save URL');
|
| 1012 |
+
} else {
|
| 1013 |
+
editor.hide();
|
| 1014 |
+
cancel_button_container.hide();
|
| 1015 |
+
url_el.show();
|
| 1016 |
+
|
| 1017 |
+
new_url = editor.val();
|
| 1018 |
+
|
| 1019 |
+
if (new_url != orig_url){
|
| 1020 |
+
//Save the changed link
|
| 1021 |
+
url_el.html('Saving changes...');
|
| 1022 |
+
|
| 1023 |
+
$.getJSON(
|
| 1024 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1025 |
+
{
|
| 1026 |
+
'action' : 'blc_edit',
|
| 1027 |
+
'link_id' : link_id,
|
| 1028 |
+
'new_url' : new_url
|
| 1029 |
+
},
|
| 1030 |
+
function (data, textStatus){
|
| 1031 |
+
var display_url = '';
|
| 1032 |
+
|
| 1033 |
+
if ( data && (typeof(data['error']) != 'undefined') ){
|
| 1034 |
+
//data.error is an error message
|
| 1035 |
+
alert(data.error);
|
| 1036 |
+
display_url = orig_url;
|
| 1037 |
+
} else {
|
| 1038 |
+
//data contains info about the performed edit
|
| 1039 |
+
if ( data.cnt_okay > 0 ){
|
| 1040 |
+
display_url = new_url;
|
| 1041 |
+
|
| 1042 |
+
url_el.attr('href', new_url);
|
| 1043 |
+
|
| 1044 |
+
if ( data.cnt_error > 0 ){
|
| 1045 |
+
var msg = "The link was successfully modifed.";
|
| 1046 |
+
msg = msg + "\nHowever, "+data.cnt_error+" instances couldn't be edited and still point to the old URL."
|
| 1047 |
+
alert(msg);
|
| 1048 |
+
} else {
|
| 1049 |
+
//Flash the row green to indicate success
|
| 1050 |
+
var oldColor = master.css('background-color');
|
| 1051 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300);
|
| 1052 |
+
|
| 1053 |
+
//Save the new ID
|
| 1054 |
+
master.find('.blc-link-id').html(data.new_link_id);
|
| 1055 |
+
//Load up the new link info (so sue me)
|
| 1056 |
+
master.next('.blc-link-details').find('td').html('<center>Loading...</center>').load(
|
| 1057 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1058 |
+
{
|
| 1059 |
+
'action' : 'blc_link_details',
|
| 1060 |
+
'link_id' : data.new_link_id
|
| 1061 |
+
}
|
| 1062 |
+
);
|
| 1063 |
+
}
|
| 1064 |
+
} else {
|
| 1065 |
+
alert("Something went wrong. The plugin failed to edit "+
|
| 1066 |
+
data.cnt_error + ' instance(s) of this link.');
|
| 1067 |
+
|
| 1068 |
+
display_url = orig_url;
|
| 1069 |
+
}
|
| 1070 |
+
};
|
| 1071 |
+
|
| 1072 |
+
//Shorten the displayed URL if it's > 50 characters
|
| 1073 |
+
if ( display_url.length > 50 ){
|
| 1074 |
+
display_url = display_url.substr(0, 47) + '...';
|
| 1075 |
+
}
|
| 1076 |
+
url_el.html(display_url);
|
| 1077 |
+
}
|
| 1078 |
+
);
|
| 1079 |
+
|
| 1080 |
+
} else {
|
| 1081 |
+
//It's the same URL, so do nothing.
|
| 1082 |
+
}
|
| 1083 |
+
edit_button.html('Edit URL');
|
| 1084 |
+
}
|
| 1085 |
+
});
|
| 1086 |
+
|
| 1087 |
+
$(".blc-cancel-button").click(function () {
|
| 1088 |
+
var master = $(this).parents('.blc-row');
|
| 1089 |
+
var url_el = $(master).find('.blc-link-url');
|
| 1090 |
+
|
| 1091 |
+
//Hide the cancel button
|
| 1092 |
+
$(this).parent().hide();
|
| 1093 |
+
//Show the un-editable URL again
|
| 1094 |
+
url_el.show();
|
| 1095 |
+
//reset and hide the editor
|
| 1096 |
+
master.find('.blc-link-editor').hide().val(url_el.attr('href'));
|
| 1097 |
+
//Set the edit button to say "Edit URL"
|
| 1098 |
+
master.find('.blc-edit-button').html('Edit URL');
|
| 1099 |
+
});
|
| 1100 |
+
|
| 1101 |
+
//The unlink button - remove the link/image from all posts, custom fields, etc.
|
| 1102 |
+
$(".blc-unlink-button").click(function () {
|
| 1103 |
+
var me = this;
|
| 1104 |
+
var master = $(me).parents('.blc-row');
|
| 1105 |
+
$(me).html('Wait...');
|
| 1106 |
+
|
| 1107 |
+
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 1108 |
+
|
| 1109 |
+
$.post(
|
| 1110 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1111 |
+
{
|
| 1112 |
+
'action' : 'blc_unlink',
|
| 1113 |
+
'link_id' : link_id
|
| 1114 |
+
},
|
| 1115 |
+
function (data, textStatus){
|
| 1116 |
+
eval('data = ' + data);
|
| 1117 |
+
|
| 1118 |
+
if ( data && ( typeof(data['ok']) != 'undefined') ){
|
| 1119 |
+
//Hide the details
|
| 1120 |
+
master.next('.blc-link-details').hide();
|
| 1121 |
+
//Flash the main row green to indicate success, then hide it.
|
| 1122 |
+
var oldColor = master.css('background-color');
|
| 1123 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: oldColor }, 300, function(){
|
| 1124 |
+
master.hide();
|
| 1125 |
+
});
|
| 1126 |
+
|
| 1127 |
+
alterLinkCounter(-1);
|
| 1128 |
+
} else {
|
| 1129 |
+
$(me).html('Unlink');
|
| 1130 |
+
//Show the error message
|
| 1131 |
+
alert(data.error);
|
| 1132 |
+
}
|
| 1133 |
+
}
|
| 1134 |
+
);
|
| 1135 |
+
});
|
| 1136 |
+
|
| 1137 |
+
//The exclude button - Add this link to the exclusion list
|
| 1138 |
+
$(".blc-exclude-button").click(function () {
|
| 1139 |
+
var me = this;
|
| 1140 |
+
var master = $(me).parents('.blc-row');
|
| 1141 |
+
var details = master.next('.blc-link-details');
|
| 1142 |
+
$(me).html('Wait...');
|
| 1143 |
+
|
| 1144 |
+
var link_id = $(me).parents('.blc-row').find('.blc-link-id').html();
|
| 1145 |
+
|
| 1146 |
+
$.post(
|
| 1147 |
+
"<?php bloginfo( 'wpurl' ); ?>/wp-admin/admin-ajax.php",
|
| 1148 |
+
{
|
| 1149 |
+
'action' : 'blc_exclude_link',
|
| 1150 |
+
'link_id' : link_id
|
| 1151 |
+
},
|
| 1152 |
+
function (data, textStatus){
|
| 1153 |
+
eval('data = ' + data);
|
| 1154 |
+
|
| 1155 |
+
if ( data && ( typeof(data['ok']) != 'undefined' ) ){
|
| 1156 |
+
|
| 1157 |
+
if ( 'broken' == blc_current_filter ){
|
| 1158 |
+
//Flash the row green to indicate success, then hide it.
|
| 1159 |
+
$(me).replaceWith('Excluded');
|
| 1160 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 200, function(){
|
| 1161 |
+
details.hide();
|
| 1162 |
+
master.hide();
|
| 1163 |
+
alterLinkCounter(-1);
|
| 1164 |
+
});
|
| 1165 |
+
master.addClass('blc-excluded-link');
|
| 1166 |
+
} else {
|
| 1167 |
+
//Flash the row green to indicate success and fade to the "excluded link" color
|
| 1168 |
+
master.animate({ backgroundColor: "#E0FFB3" }, 200).animate({ backgroundColor: '#E2E2E2' }, 300);
|
| 1169 |
+
master.addClass('blc-excluded-link');
|
| 1170 |
+
$(me).replaceWith('Excluded');
|
| 1171 |
+
}
|
| 1172 |
+
} else {
|
| 1173 |
+
$(me).html('Exclude');
|
| 1174 |
+
alert(data.error);
|
| 1175 |
+
}
|
| 1176 |
+
}
|
| 1177 |
+
);
|
| 1178 |
+
});
|
| 1179 |
+
|
| 1180 |
+
});
|
| 1181 |
+
|
| 1182 |
+
</script>
|
| 1183 |
+
<?php
|
| 1184 |
+
}
|
| 1185 |
+
|
| 1186 |
+
function link_details_row($link){
|
| 1187 |
+
?>
|
| 1188 |
+
<span id='post_date_full' style='display:none;'><?php
|
| 1189 |
+
print $link['post_date'];
|
| 1190 |
+
?></span>
|
| 1191 |
+
<span id='check_date_full' style='display:none;'><?php
|
| 1192 |
+
print $link['last_check'];
|
| 1193 |
+
?></span>
|
| 1194 |
+
<ol style='list-style-type: none; width: 50%; float: right;'>
|
| 1195 |
+
<li><strong>Log :</strong>
|
| 1196 |
+
<span class='blc_log'><?php
|
| 1197 |
+
print nl2br($link['log']);
|
| 1198 |
+
?></span></li>
|
| 1199 |
+
</ol>
|
| 1200 |
+
|
| 1201 |
+
<ol style='list-style-type: none; padding-left: 2px;'>
|
| 1202 |
+
<?php if ( !empty($link['post_date']) ) { ?>
|
| 1203 |
+
<li><strong>Post published on :</strong>
|
| 1204 |
+
<span class='post_date'><?php
|
| 1205 |
+
print strftime("%B %d, %Y",strtotime($link['post_date']));
|
| 1206 |
+
?></span></li>
|
| 1207 |
+
<?php } ?>
|
| 1208 |
+
<li><strong>Link last checked :</strong>
|
| 1209 |
+
<span class='check_date'><?php
|
| 1210 |
+
$last_check = strtotime($link['last_check']);
|
| 1211 |
+
if ( $last_check < strtotime('-10 years') ){
|
| 1212 |
+
echo 'Never';
|
| 1213 |
+
} else {
|
| 1214 |
+
echo strftime( "%B %d, %Y", $last_check );
|
| 1215 |
+
}
|
| 1216 |
+
?></span></li>
|
| 1217 |
+
|
| 1218 |
+
<li><strong>HTTP code :</strong>
|
| 1219 |
+
<span class='http_code'><?php
|
| 1220 |
+
print $link['http_code'];
|
| 1221 |
+
?></span></li>
|
| 1222 |
+
|
| 1223 |
+
<li><strong>Response time :</strong>
|
| 1224 |
+
<span class='request_duration'><?php
|
| 1225 |
+
printf('%2.3f seconds', $link['request_duration']);
|
| 1226 |
+
?></span></li>
|
| 1227 |
+
|
| 1228 |
+
<li><strong>Final URL :</strong>
|
| 1229 |
+
<span class='final_url'><?php
|
| 1230 |
+
print $link['final_url'];
|
| 1231 |
+
?></span></li>
|
| 1232 |
+
|
| 1233 |
+
<li><strong>Redirect count :</strong>
|
| 1234 |
+
<span class='redirect_count'><?php
|
| 1235 |
+
print $link['redirect_count'];
|
| 1236 |
+
?></span></li>
|
| 1237 |
+
|
| 1238 |
+
<li><strong>Instance count :</strong>
|
| 1239 |
+
<span class='instance_count'><?php
|
| 1240 |
+
print $link['instance_count'];
|
| 1241 |
+
?></span></li>
|
| 1242 |
+
|
| 1243 |
+
<?php if ( intval( $link['check_count'] ) > 0 ){ ?>
|
| 1244 |
+
<li><br/>This link has failed
|
| 1245 |
+
<span class='check_count'><?php
|
| 1246 |
+
echo $link['check_count'];
|
| 1247 |
+
if ( intval($link['check_count'])==1 ){
|
| 1248 |
+
echo ' time';
|
| 1249 |
+
} else {
|
| 1250 |
+
echo ' times';
|
| 1251 |
+
}
|
| 1252 |
+
?></span>.</li>
|
| 1253 |
+
<?php } ?>
|
| 1254 |
+
</ol>
|
| 1255 |
+
<?php
|
| 1256 |
+
}
|
| 1257 |
+
|
| 1258 |
+
/**
|
| 1259 |
+
* ws_broken_link_checker::cleanup_links()
|
| 1260 |
+
* Remove orphaned links that have no corresponding instances
|
| 1261 |
+
*
|
| 1262 |
+
* @param int $link_id (optional) Only check this link
|
| 1263 |
+
* @return bool
|
| 1264 |
+
*/
|
| 1265 |
+
function cleanup_links( $link_id = null ){
|
| 1266 |
+
global $wpdb;
|
| 1267 |
+
|
| 1268 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_links
|
| 1269 |
+
USING {$wpdb->prefix}blc_links LEFT JOIN {$wpdb->prefix}blc_instances
|
| 1270 |
+
ON {$wpdb->prefix}blc_instances.link_id = {$wpdb->prefix}blc_links.link_id
|
| 1271 |
+
WHERE
|
| 1272 |
+
{$wpdb->prefix}blc_instances.link_id IS NULL";
|
| 1273 |
+
|
| 1274 |
+
if ( $link_id !==null ) {
|
| 1275 |
+
$q .= " AND {$wpdb->prefix}blc_links.link_id = " . intval( $link_id );
|
| 1276 |
+
}
|
| 1277 |
+
|
| 1278 |
+
return $wpdb->query( $q );
|
| 1279 |
+
}
|
| 1280 |
+
|
| 1281 |
+
/**
|
| 1282 |
+
* ws_broken_link_checker::cleanup_instances()
|
| 1283 |
+
* Remove instances that reference invalid posts or bookmarks
|
| 1284 |
+
*
|
| 1285 |
+
* @return bool
|
| 1286 |
+
*/
|
| 1287 |
+
function cleanup_instances(){
|
| 1288 |
+
global $wpdb;
|
| 1289 |
+
|
| 1290 |
+
//Delete all instances that reference non-existent posts
|
| 1291 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1292 |
+
USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->posts} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->posts}.ID
|
| 1293 |
+
WHERE
|
| 1294 |
+
{$wpdb->posts}.ID IS NULL
|
| 1295 |
+
AND ( ( {$wpdb->prefix}blc_instances.source_type = 'post' ) OR ( {$wpdb->prefix}blc_instances.source_type = 'custom_field' ) )";
|
| 1296 |
+
$rez = $wpdb->query($q);
|
| 1297 |
+
|
| 1298 |
+
//Delete all instances that reference non-existant bookmarks
|
| 1299 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1300 |
+
USING {$wpdb->prefix}blc_instances LEFT JOIN {$wpdb->links} ON {$wpdb->prefix}blc_instances.source_id = {$wpdb->links}.link_id
|
| 1301 |
+
WHERE
|
| 1302 |
+
{$wpdb->links}.link_id IS NULL
|
| 1303 |
+
AND {$wpdb->prefix}blc_instances.source_type = 'blogroll' ";
|
| 1304 |
+
$rez2 = $wpdb->query($q);
|
| 1305 |
+
|
| 1306 |
+
return $rez and $rez2;
|
| 1307 |
+
}
|
| 1308 |
+
|
| 1309 |
+
/**
|
| 1310 |
+
* ws_broken_link_checker::parse_post()
|
| 1311 |
+
* Parse a post for links and save them to the DB.
|
| 1312 |
+
*
|
| 1313 |
+
* @param string $content Post content
|
| 1314 |
+
* @param int $post_id Post ID
|
| 1315 |
+
* @return void
|
| 1316 |
+
*/
|
| 1317 |
+
function parse_post($content, $post_id){
|
| 1318 |
+
//remove all <code></code> blocks first
|
| 1319 |
+
$content = preg_replace('/<code[^>]*>.+?<\/code>/si', ' ', $content);
|
| 1320 |
+
//Get the post permalink - it's used to resolve relative URLs
|
| 1321 |
+
$permalink = get_permalink( $post_id );
|
| 1322 |
+
|
| 1323 |
+
//Find links
|
| 1324 |
+
if(preg_match_all(blcUtility::link_pattern(), $content, $matches, PREG_SET_ORDER)){
|
| 1325 |
+
foreach($matches as $link){
|
| 1326 |
+
$url = $link[3];
|
| 1327 |
+
$text = strip_tags( $link[5] );
|
| 1328 |
+
//FB::log($url, "Found link");
|
| 1329 |
+
|
| 1330 |
+
$url = blcUtility::normalize_url($url, $permalink);
|
| 1331 |
+
//Skip invalid links
|
| 1332 |
+
if ( !$url || (strlen($url)<6) ) continue;
|
| 1333 |
+
|
| 1334 |
+
//Create or load the link
|
| 1335 |
+
$link_obj = new blcLink($url);
|
| 1336 |
+
//Add & save a new instance
|
| 1337 |
+
$link_obj->add_instance($post_id, 'post', $text, 'link');
|
| 1338 |
+
}
|
| 1339 |
+
};
|
| 1340 |
+
|
| 1341 |
+
//Find images (<img src=...>)
|
| 1342 |
+
if(preg_match_all(blcUtility::img_pattern(), $content, $matches, PREG_SET_ORDER)){
|
| 1343 |
+
foreach($matches as $img){
|
| 1344 |
+
$url = $img[3];
|
| 1345 |
+
//FB::log($url, "Found image");
|
| 1346 |
+
|
| 1347 |
+
$url = blcUtility::normalize_url($url, $permalink);
|
| 1348 |
+
if ( !$url || (strlen($url)<6) ) continue; //skip invalid URLs
|
| 1349 |
+
|
| 1350 |
+
//Create or load the link
|
| 1351 |
+
$link = new blcLink($url);
|
| 1352 |
+
//Add & save a new image instance
|
| 1353 |
+
$link->add_instance($post_id, 'post', '', 'image');
|
| 1354 |
+
}
|
| 1355 |
+
};
|
| 1356 |
+
}
|
| 1357 |
+
|
| 1358 |
+
/**
|
| 1359 |
+
* ws_broken_link_checker::parse_post_meta()
|
| 1360 |
+
* Parse a post's custom fields for links and save them in the DB.
|
| 1361 |
+
*
|
| 1362 |
+
* @param id $post_id
|
| 1363 |
+
* @return void
|
| 1364 |
+
*/
|
| 1365 |
+
function parse_post_meta($post_id){
|
| 1366 |
+
//Get all custom fields of this post
|
| 1367 |
+
$custom_fields = get_post_custom( $post_id );
|
| 1368 |
+
//FB::log($custom_fields, "Custom fields loaded");
|
| 1369 |
+
|
| 1370 |
+
//Parse the enabled fields
|
| 1371 |
+
foreach( $this->conf->options['custom_fields'] as $field ){
|
| 1372 |
+
if ( !isset($custom_fields[$field]) ) continue;
|
| 1373 |
+
|
| 1374 |
+
//FB::log($field, "Parsing field");
|
| 1375 |
+
|
| 1376 |
+
$values = $custom_fields[$field];
|
| 1377 |
+
if ( !is_array( $values ) ) $values = array($values);
|
| 1378 |
+
|
| 1379 |
+
foreach( $values as $value ){
|
| 1380 |
+
|
| 1381 |
+
//Attempt to parse the $value as URL
|
| 1382 |
+
$url = blcUtility::normalize_url($value);
|
| 1383 |
+
if ( empty($url) ){
|
| 1384 |
+
//FB::warn($value, "Invalid URL in custom field ".$field);
|
| 1385 |
+
continue;
|
| 1386 |
+
}
|
| 1387 |
+
|
| 1388 |
+
//FB::log($url, "Found URL");
|
| 1389 |
+
$link = new blcLink( $url );
|
| 1390 |
+
//FB::log($link, 'Created/loaded link');
|
| 1391 |
+
$inst = $link->add_instance( $post_id, 'custom_field', $field, 'link' );
|
| 1392 |
+
//FB::log($inst, 'Created instance');
|
| 1393 |
+
}
|
| 1394 |
+
}
|
| 1395 |
+
|
| 1396 |
+
}
|
| 1397 |
+
|
| 1398 |
+
function parse_blogroll_link( $the_link ){
|
| 1399 |
+
//FB::log($the_link, "Parsing blogroll link");
|
| 1400 |
+
|
| 1401 |
+
//Attempt to parse the URL
|
| 1402 |
+
$url = blcUtility::normalize_url( $the_link['link_url'] );
|
| 1403 |
+
if ( empty($url) ){
|
| 1404 |
+
//FB::warn( $the_link['link_url'], "Invalid URL in for a blogroll link".$the_link['link_name'] );
|
| 1405 |
+
return false;
|
| 1406 |
+
}
|
| 1407 |
+
|
| 1408 |
+
//FB::log($url, "Found URL");
|
| 1409 |
+
$link = new blcLink( $url );
|
| 1410 |
+
return $link->add_instance( $the_link['link_id'], 'blogroll', $the_link['link_name'], 'link' );
|
| 1411 |
+
}
|
| 1412 |
+
|
| 1413 |
+
function start_timer(){
|
| 1414 |
+
$this->execution_start_time = microtime_float();
|
| 1415 |
+
}
|
| 1416 |
+
|
| 1417 |
+
function execution_time(){
|
| 1418 |
+
return microtime_float() - $this->execution_start_time;
|
| 1419 |
+
}
|
| 1420 |
+
|
| 1421 |
+
/**
|
| 1422 |
+
* ws_broken_link_checker::work()
|
| 1423 |
+
* The main worker function that does all kinds of things.
|
| 1424 |
+
*
|
| 1425 |
+
* @return void
|
| 1426 |
+
*/
|
| 1427 |
+
function work(){
|
| 1428 |
+
global $wpdb;
|
| 1429 |
+
|
| 1430 |
+
if ( !$this->acquire_lock() ){
|
| 1431 |
+
//FB::warn("Another instance of BLC is already working. Stop.");
|
| 1432 |
+
return false;
|
| 1433 |
+
}
|
| 1434 |
+
|
| 1435 |
+
$this->start_timer();
|
| 1436 |
+
|
| 1437 |
+
$max_execution_time = $this->conf->options['max_execution_time'];
|
| 1438 |
+
|
| 1439 |
+
/*****************************************
|
| 1440 |
+
Preparation
|
| 1441 |
+
******************************************/
|
| 1442 |
+
// Check for safe mode
|
| 1443 |
+
if( ini_get('safe_mode') ){
|
| 1444 |
+
// Do it the safe mode way
|
| 1445 |
+
$t=ini_get('max_execution_time');
|
| 1446 |
+
if ($t && ($t < $max_execution_time))
|
| 1447 |
+
$max_execution_time = $t-1;
|
| 1448 |
+
} else {
|
| 1449 |
+
// Do it the regular way
|
| 1450 |
+
@set_time_limit( $max_execution_time * 2 ); //x2 should be plenty, running any longer would mean a glitch.
|
| 1451 |
+
}
|
| 1452 |
+
@ignore_user_abort(true);
|
| 1453 |
+
|
| 1454 |
+
$check_threshold = date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 1455 |
+
$recheck_threshold = date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
| 1456 |
+
|
| 1457 |
+
$orphans_possible = false;
|
| 1458 |
+
|
| 1459 |
+
$still_need_resynch = $this->conf->options['need_resynch'];
|
| 1460 |
+
|
| 1461 |
+
/*****************************************
|
| 1462 |
+
Parse posts and bookmarks
|
| 1463 |
+
******************************************/
|
| 1464 |
+
|
| 1465 |
+
if ( $this->conf->options['need_resynch'] ) {
|
| 1466 |
+
|
| 1467 |
+
//FB::log("Looking for posts and bookmarks that need parsing...");
|
| 1468 |
+
|
| 1469 |
+
$tsynch = $wpdb->prefix.'blc_synch';
|
| 1470 |
+
$tposts = $wpdb->posts;
|
| 1471 |
+
$tlinks = $wpdb->links;
|
| 1472 |
+
|
| 1473 |
+
$synch_q = "SELECT $tsynch.source_id, $tsynch.source_type, $tposts.post_content, $tlinks.link_url, $tlinks.link_id, $tlinks.link_name
|
| 1474 |
+
|
| 1475 |
+
FROM
|
| 1476 |
+
$tsynch LEFT JOIN $tposts
|
| 1477 |
+
ON ($tposts.id = $tsynch.source_id AND $tsynch.source_type='post')
|
| 1478 |
+
LEFT JOIN $tlinks
|
| 1479 |
+
ON ($tlinks.link_id = $tsynch.source_id AND $tsynch.source_type='blogroll')
|
| 1480 |
+
|
| 1481 |
+
WHERE
|
| 1482 |
+
$tsynch.synched = 0
|
| 1483 |
+
|
| 1484 |
+
LIMIT 50";
|
| 1485 |
+
|
| 1486 |
+
while ( $rows = $wpdb->get_results($synch_q, ARRAY_A) ) {
|
| 1487 |
+
|
| 1488 |
+
//FB::log("Found ".count($rows)." items to analyze.");
|
| 1489 |
+
|
| 1490 |
+
foreach ($rows as $row) {
|
| 1491 |
+
|
| 1492 |
+
if ( $row['source_type'] == 'post' ){
|
| 1493 |
+
|
| 1494 |
+
//FB::log("Parsing post ".$row['source_id']);
|
| 1495 |
+
|
| 1496 |
+
//Remove instances associated with this post
|
| 1497 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1498 |
+
WHERE source_id = %d AND (source_type = 'post' OR source_type='custom_field')";
|
| 1499 |
+
$q = $wpdb->prepare($q, intval($row['source_id']));
|
| 1500 |
+
|
| 1501 |
+
//FB::log($q, "Executing query");
|
| 1502 |
+
|
| 1503 |
+
if ( $wpdb->query( $q ) === false ){
|
| 1504 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 1505 |
+
}
|
| 1506 |
+
|
| 1507 |
+
//Gather links and images from the post
|
| 1508 |
+
$this->parse_post( $row['post_content'], $row['source_id'] );
|
| 1509 |
+
//Gather links from custom fields
|
| 1510 |
+
$this->parse_post_meta( $row['source_id'] );
|
| 1511 |
+
|
| 1512 |
+
//Some link records might be orhpaned now
|
| 1513 |
+
$orphans_possible = true;
|
| 1514 |
+
|
| 1515 |
+
} else {
|
| 1516 |
+
|
| 1517 |
+
//FB::log("Parsing bookmark ".$row['source_id']);
|
| 1518 |
+
|
| 1519 |
+
//Remove instances associated with this bookmark
|
| 1520 |
+
$q = "DELETE FROM {$wpdb->prefix}blc_instances
|
| 1521 |
+
WHERE source_id = %d AND source_type = 'blogroll'";
|
| 1522 |
+
$q = $wpdb->prepare($q, intval($row['source_id']));
|
| 1523 |
+
//FB::log($q, "Executing query");
|
| 1524 |
+
|
| 1525 |
+
if ( $wpdb->query( $q ) === false ){
|
| 1526 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 1527 |
+
}
|
| 1528 |
+
|
| 1529 |
+
//(Re)add the instance and link
|
| 1530 |
+
$this->parse_blogroll_link( $row );
|
| 1531 |
+
|
| 1532 |
+
//Some link records might be orhpaned now
|
| 1533 |
+
$orphans_possible = true;
|
| 1534 |
+
|
| 1535 |
+
}
|
| 1536 |
+
|
| 1537 |
+
//Update the table to indicate the item has been parsed
|
| 1538 |
+
$this->mark_synched( $row['source_id'], $row['source_type'] );
|
| 1539 |
+
|
| 1540 |
+
//Check if we still have some execution time left
|
| 1541 |
+
if( $this->execution_time() > $max_execution_time ){
|
| 1542 |
+
//FB::log('The alloted execution time has run out');
|
| 1543 |
+
$this->cleanup_links();
|
| 1544 |
+
$this->release_lock();
|
| 1545 |
+
return;
|
| 1546 |
+
}
|
| 1547 |
+
|
| 1548 |
+
}
|
| 1549 |
+
|
| 1550 |
+
}
|
| 1551 |
+
|
| 1552 |
+
//FB::log('No unparsed items found.');
|
| 1553 |
+
$still_need_resynch = false;
|
| 1554 |
+
|
| 1555 |
+
if ( $wpdb->last_error ){
|
| 1556 |
+
//FB::error($wpdb->last_error, "Database error");
|
| 1557 |
+
}
|
| 1558 |
+
|
| 1559 |
+
} else {
|
| 1560 |
+
//FB::log('Resynch not required.');
|
| 1561 |
+
}
|
| 1562 |
+
|
| 1563 |
+
/******************************************
|
| 1564 |
+
Resynch done?
|
| 1565 |
+
*******************************************/
|
| 1566 |
+
if ( $this->conf->options['need_resynch'] && !$still_need_resynch ){
|
| 1567 |
+
$this->conf->options['need_resynch'] = $still_need_resynch;
|
| 1568 |
+
$this->conf->save_options();
|
| 1569 |
+
}
|
| 1570 |
+
|
| 1571 |
+
/******************************************
|
| 1572 |
+
Remove orphaned links
|
| 1573 |
+
*******************************************/
|
| 1574 |
+
|
| 1575 |
+
if ( $orphans_possible ) {
|
| 1576 |
+
//FB::log('Cleaning up the link table.');
|
| 1577 |
+
$this->cleanup_links();
|
| 1578 |
+
}
|
| 1579 |
+
|
| 1580 |
+
//Check if we still have some execution time left
|
| 1581 |
+
if( $this->execution_time() > $max_execution_time ){
|
| 1582 |
+
//FB::log('The alloted execution time has run out');
|
| 1583 |
+
$this->release_lock();
|
| 1584 |
+
return;
|
| 1585 |
+
}
|
| 1586 |
+
|
| 1587 |
+
/*****************************************
|
| 1588 |
+
Check links
|
| 1589 |
+
******************************************/
|
| 1590 |
+
//FB::log('Looking for links to check (threshold : '.$check_threshold.')...');
|
| 1591 |
+
|
| 1592 |
+
//Select some links that haven't been checked for a long time or
|
| 1593 |
+
//that are broken and need to be re-checked again.
|
| 1594 |
+
|
| 1595 |
+
//Note : This is a slow query, but AFAIK there is no way to speed it up.
|
| 1596 |
+
//I could put an index on last_check, but that value is almost certainly unique
|
| 1597 |
+
//for each row so it wouldn't be much better than a full table scan.
|
| 1598 |
+
$q = "SELECT *, ( last_check < %s ) AS meets_check_threshold
|
| 1599 |
+
FROM {$wpdb->prefix}blc_links
|
| 1600 |
+
WHERE
|
| 1601 |
+
( last_check < %s )
|
| 1602 |
+
OR
|
| 1603 |
+
(
|
| 1604 |
+
( http_code >= 400 OR http_code < 200 OR timeout = 1)
|
| 1605 |
+
AND check_count < %d
|
| 1606 |
+
AND check_count > 0
|
| 1607 |
+
AND last_check < %s
|
| 1608 |
+
)
|
| 1609 |
+
ORDER BY last_check ASC
|
| 1610 |
+
LIMIT 50";
|
| 1611 |
+
$link_q = $wpdb->prepare($q, $check_threshold, $check_threshold, $this->conf->options['recheck_count'], $recheck_threshold);
|
| 1612 |
+
//FB::log($link_q);
|
| 1613 |
+
|
| 1614 |
+
while ( $links = $wpdb->get_results($link_q, ARRAY_A) ){
|
| 1615 |
+
|
| 1616 |
+
//some unchecked links found
|
| 1617 |
+
//FB::log("Checking ".count($links)." link(s)");
|
| 1618 |
+
|
| 1619 |
+
foreach ($links as $link) {
|
| 1620 |
+
$link_obj = new blcLink($link);
|
| 1621 |
+
|
| 1622 |
+
//Does this link need to be checked?
|
| 1623 |
+
if ( !$this->is_excluded( $link['url'] ) ) {
|
| 1624 |
+
//Yes, do it
|
| 1625 |
+
//FB::log("Checking link {$link[link_id]}");
|
| 1626 |
+
$link_obj->check();
|
| 1627 |
+
$link_obj->save();
|
| 1628 |
+
} else {
|
| 1629 |
+
//Nope, mark it as already checked.
|
| 1630 |
+
//FB::info("The URL {$link_obj->url} is excluded, marking link {$link_obj->link_id} as already checked.");
|
| 1631 |
+
$link_obj->last_check = date('Y-m-d H:i:s');
|
| 1632 |
+
$link_obj->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
| 1633 |
+
$link_obj->timeout = false;
|
| 1634 |
+
$link_obj->request_duration = 0;
|
| 1635 |
+
$link_obj->log = "This link wasn't checked because a matching keyword was found on your exclusion list.";
|
| 1636 |
+
$link_obj->save();
|
| 1637 |
+
}
|
| 1638 |
+
|
| 1639 |
+
//Check if we still have some execution time left
|
| 1640 |
+
if( $this->execution_time() > $max_execution_time ){
|
| 1641 |
+
//FB::log('The alloted execution time has run out');
|
| 1642 |
+
$this->release_lock();
|
| 1643 |
+
return;
|
| 1644 |
+
}
|
| 1645 |
+
}
|
| 1646 |
+
}
|
| 1647 |
+
//FB::log('No links need to be checked right now.');
|
| 1648 |
+
|
| 1649 |
+
$this->release_lock();
|
| 1650 |
+
//FB::log('All done.');
|
| 1651 |
+
}
|
| 1652 |
+
|
| 1653 |
+
function ajax_full_status( ){
|
| 1654 |
+
$status = $this->get_status();
|
| 1655 |
+
$text = $this->status_text( $status );
|
| 1656 |
+
|
| 1657 |
+
echo json_encode( array(
|
| 1658 |
+
'text' => $text,
|
| 1659 |
+
'status' => $status,
|
| 1660 |
+
) );
|
| 1661 |
+
|
| 1662 |
+
die();
|
| 1663 |
+
}
|
| 1664 |
+
|
| 1665 |
+
/**
|
| 1666 |
+
* ws_broken_link_checker::status_text()
|
| 1667 |
+
* Generates a status message based on the status info in $status
|
| 1668 |
+
*
|
| 1669 |
+
* @param array $status
|
| 1670 |
+
* @return string
|
| 1671 |
+
*/
|
| 1672 |
+
function status_text( $status ){
|
| 1673 |
+
$text = '';
|
| 1674 |
+
|
| 1675 |
+
if( $status['broken_links'] > 0 ){
|
| 1676 |
+
$text .= sprintf( "<a href='%stools.php?page=view-broken-links' title='View broken links'><strong>Found %d broken link%s</strong></a>",
|
| 1677 |
+
get_option('wpurl'), $status['broken_links'], ( $status['broken_links'] == 1 )?'':'s' );
|
| 1678 |
+
} else {
|
| 1679 |
+
$text .= "No broken links found.";
|
| 1680 |
+
}
|
| 1681 |
+
|
| 1682 |
+
$text .= "<br/>";
|
| 1683 |
+
|
| 1684 |
+
if( $status['unchecked_links'] > 0) {
|
| 1685 |
+
$text .= sprintf( '%d URL%s in the work queue', $status['unchecked_links'], ($status['unchecked_links'] == 1)?'':'s' );
|
| 1686 |
+
} else {
|
| 1687 |
+
$text .= "No URLs in the work queue.";
|
| 1688 |
+
}
|
| 1689 |
+
|
| 1690 |
+
$text .= "<br/>";
|
| 1691 |
+
if ( $status['known_links'] > 0 ){
|
| 1692 |
+
$text .= sprintf( "Detected %d unique URL%s in %d link%s",
|
| 1693 |
+
$status['known_links'], $status['known_links'] == 1 ? '' : 's',
|
| 1694 |
+
$status['known_instances'], $status['known_instances'] == 1 ? '' : 's'
|
| 1695 |
+
);
|
| 1696 |
+
if ($this->conf->options['need_resynch']){
|
| 1697 |
+
$text .= ' and still searching...';
|
| 1698 |
+
} else {
|
| 1699 |
+
$text .= '.';
|
| 1700 |
+
}
|
| 1701 |
+
} else {
|
| 1702 |
+
if ($this->conf->options['need_resynch']){
|
| 1703 |
+
$text .= 'Searching your blog for links...';
|
| 1704 |
+
} else {
|
| 1705 |
+
$text .= 'No links detected.';
|
| 1706 |
+
}
|
| 1707 |
+
}
|
| 1708 |
+
|
| 1709 |
+
return $text;
|
| 1710 |
+
}
|
| 1711 |
+
|
| 1712 |
+
function ajax_dashboard_status(){
|
| 1713 |
+
//Just display the full status.
|
| 1714 |
+
$this->ajax_full_status( false );
|
| 1715 |
+
/*
|
| 1716 |
+
global $wpdb;
|
| 1717 |
+
|
| 1718 |
+
//displays a notification if broken links have been found
|
| 1719 |
+
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1720 |
+
WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 )";
|
| 1721 |
+
$broken_links = $wpdb->get_var($q);
|
| 1722 |
+
|
| 1723 |
+
|
| 1724 |
+
if($broken_links>0){
|
| 1725 |
+
printf( "<a href='%stools.php?page=view-broken-links' title='View broken links'><strong>Found %d broken link%s</strong></a>",
|
| 1726 |
+
get_option('wpurl'), $broken_links, ($broken_links==1)?'':'s' );
|
| 1727 |
+
} else {
|
| 1728 |
+
echo "No broken links found.";
|
| 1729 |
+
}
|
| 1730 |
+
die();
|
| 1731 |
+
*/
|
| 1732 |
+
}
|
| 1733 |
+
|
| 1734 |
+
/**
|
| 1735 |
+
* ws_broken_link_checker::get_status()
|
| 1736 |
+
* Returns an array with various status information about the plugin. Array key reference:
|
| 1737 |
+
* check_threshold - date/time; links checked before this threshold should be checked again.
|
| 1738 |
+
* recheck_threshold - date/time; broken links checked before this threshold should be re-checked.
|
| 1739 |
+
* known_links - the number of detected unique URLs (a misleading name, yes).
|
| 1740 |
+
* known_instances - the number of detected link instances, i.e. actual link elements in posts and other places.
|
| 1741 |
+
* broken_links - the number of detected broken links.
|
| 1742 |
+
* unchecked_links - the number of URLs that need to be checked ASAP; based on check_threshold and recheck_threshold.
|
| 1743 |
+
*
|
| 1744 |
+
* @return array
|
| 1745 |
+
*/
|
| 1746 |
+
function get_status(){
|
| 1747 |
+
global $wpdb;
|
| 1748 |
+
|
| 1749 |
+
$check_threshold=date('Y-m-d H:i:s', strtotime('-'.$this->conf->options['check_threshold'].' hours'));
|
| 1750 |
+
$recheck_threshold=date('Y-m-d H:i:s', strtotime('-20 minutes'));
|
| 1751 |
+
|
| 1752 |
+
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links WHERE 1";
|
| 1753 |
+
$known_links = $wpdb->get_var($q);
|
| 1754 |
+
|
| 1755 |
+
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_instances WHERE 1";
|
| 1756 |
+
$known_instances = $wpdb->get_var($q);
|
| 1757 |
+
|
| 1758 |
+
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1759 |
+
WHERE check_count > 0 AND ( http_code < 200 OR http_code >= 400 OR timeout = 1 ) AND ( http_code <> ".BLC_CHECKING." )";
|
| 1760 |
+
$broken_links = $wpdb->get_var($q);
|
| 1761 |
+
|
| 1762 |
+
$q = "SELECT count(*) FROM {$wpdb->prefix}blc_links
|
| 1763 |
+
WHERE
|
| 1764 |
+
( ( last_check < '$check_threshold' ) OR
|
| 1765 |
+
(
|
| 1766 |
+
( http_code >= 400 OR http_code < 200 )
|
| 1767 |
+
AND check_count < 3
|
| 1768 |
+
AND last_check < '$recheck_threshold' )
|
| 1769 |
+
)";
|
| 1770 |
+
$unchecked_links = $wpdb->get_var($q);
|
| 1771 |
+
|
| 1772 |
+
return array(
|
| 1773 |
+
'check_threshold' => $check_threshold,
|
| 1774 |
+
'recheck_threshold' => $recheck_threshold,
|
| 1775 |
+
'known_links' => $known_links,
|
| 1776 |
+
'known_instances' => $known_instances,
|
| 1777 |
+
'broken_links' => $broken_links,
|
| 1778 |
+
'unchecked_links' => $unchecked_links,
|
| 1779 |
+
);
|
| 1780 |
+
}
|
| 1781 |
+
|
| 1782 |
+
function ajax_work(){
|
| 1783 |
+
//Run the worker function
|
| 1784 |
+
$this->work();
|
| 1785 |
+
die();
|
| 1786 |
+
}
|
| 1787 |
+
|
| 1788 |
+
function ajax_discard(){
|
| 1789 |
+
//TODO:Rewrite to use JSON instead of plaintext
|
| 1790 |
+
if (!current_user_can('edit_others_posts')){
|
| 1791 |
+
die( "You're not allowed to do that!" );
|
| 1792 |
+
}
|
| 1793 |
+
|
| 1794 |
+
if ( isset($_POST['link_id']) ){
|
| 1795 |
+
//Load the link
|
| 1796 |
+
$link = new blcLink( intval($_POST['link_id']) );
|
| 1797 |
+
|
| 1798 |
+
if ( !$link->valid() ){
|
| 1799 |
+
die("Oops, I can't find the link ".intval($_POST['link_id']) );
|
| 1800 |
+
}
|
| 1801 |
+
//Make it appear "not broken"
|
| 1802 |
+
$link->last_check = date('Y-m-d H:i:s');
|
| 1803 |
+
$link->http_code = 200;
|
| 1804 |
+
$link->timeout = 0;
|
| 1805 |
+
$link->check_count = 0;
|
| 1806 |
+
$link->log = "This link was manually marked as working by the user.";
|
| 1807 |
+
|
| 1808 |
+
//Save the changes
|
| 1809 |
+
if ( $link->save() ){
|
| 1810 |
+
die("OK");
|
| 1811 |
+
} else {
|
| 1812 |
+
die("Oops, couldn't modify the link!");
|
| 1813 |
+
}
|
| 1814 |
+
} else {
|
| 1815 |
+
die("Error : link_id not specified");
|
| 1816 |
+
}
|
| 1817 |
+
}
|
| 1818 |
+
|
| 1819 |
+
function ajax_edit(){
|
| 1820 |
+
if (!current_user_can('edit_others_posts')){
|
| 1821 |
+
die( json_encode( array(
|
| 1822 |
+
'error' => "You're not allowed to do that!"
|
| 1823 |
+
)));
|
| 1824 |
+
}
|
| 1825 |
+
|
| 1826 |
+
if ( isset($_GET['link_id']) && !empty($_GET['new_url']) ){
|
| 1827 |
+
//Load the link
|
| 1828 |
+
$link = new blcLink( intval($_GET['link_id']) );
|
| 1829 |
+
|
| 1830 |
+
if ( !$link->valid() ){
|
| 1831 |
+
die( json_encode( array(
|
| 1832 |
+
'error' => "Oops, I can't find the link ".intval($_GET['link_id'])
|
| 1833 |
+
)));
|
| 1834 |
+
}
|
| 1835 |
+
|
| 1836 |
+
$new_url = blcUtility::normalize_url($_GET['new_url']);
|
| 1837 |
+
if ( !$new_url ){
|
| 1838 |
+
die( json_encode( array(
|
| 1839 |
+
'error' => "Oops, the new URL is invalid!"
|
| 1840 |
+
)));
|
| 1841 |
+
}
|
| 1842 |
+
|
| 1843 |
+
//Try and edit the link
|
| 1844 |
+
$rez = $link->edit($new_url);
|
| 1845 |
+
|
| 1846 |
+
if ( $rez == false ){
|
| 1847 |
+
die( json_encode( array(
|
| 1848 |
+
'error' => "An unexpected error occured!"
|
| 1849 |
+
)));
|
| 1850 |
+
} else {
|
| 1851 |
+
$rez['ok'] = 'OK';
|
| 1852 |
+
die( json_encode($rez) );
|
| 1853 |
+
}
|
| 1854 |
+
|
| 1855 |
+
} else {
|
| 1856 |
+
die( json_encode( array(
|
| 1857 |
+
'error' => "Error : link_id or new_url not specified"
|
| 1858 |
+
)));
|
| 1859 |
+
}
|
| 1860 |
+
}
|
| 1861 |
+
|
| 1862 |
+
function ajax_unlink(){
|
| 1863 |
+
if (!current_user_can('edit_others_posts')){
|
| 1864 |
+
die( json_encode( array(
|
| 1865 |
+
'error' => "You're not allowed to do that!"
|
| 1866 |
+
)));
|
| 1867 |
+
}
|
| 1868 |
+
|
| 1869 |
+
if ( isset($_POST['link_id']) ){
|
| 1870 |
+
//Load the link
|
| 1871 |
+
$link = new blcLink( intval($_POST['link_id']) );
|
| 1872 |
+
|
| 1873 |
+
if ( !$link->valid() ){
|
| 1874 |
+
die( json_encode( array(
|
| 1875 |
+
'error' => "Oops, I can't find the link ".intval($_POST['link_id'])
|
| 1876 |
+
)));
|
| 1877 |
+
}
|
| 1878 |
+
|
| 1879 |
+
//Try and unlink it
|
| 1880 |
+
if ( $link->unlink() ){
|
| 1881 |
+
die( json_encode( array(
|
| 1882 |
+
'ok' => "URL {$link->url} was removed."
|
| 1883 |
+
)));
|
| 1884 |
+
} else {
|
| 1885 |
+
die( json_encode( array(
|
| 1886 |
+
'error' => "The plugin failed to remove the link."
|
| 1887 |
+
)));
|
| 1888 |
+
}
|
| 1889 |
+
|
| 1890 |
+
} else {
|
| 1891 |
+
die( json_encode( array(
|
| 1892 |
+
'error' => "Error : link_id not specified"
|
| 1893 |
+
)));
|
| 1894 |
+
}
|
| 1895 |
+
}
|
| 1896 |
+
|
| 1897 |
+
function ajax_link_details(){
|
| 1898 |
+
global $wpdb;
|
| 1899 |
+
|
| 1900 |
+
if (!current_user_can('edit_others_posts')){
|
| 1901 |
+
die("You don't have sufficient privileges to access this information!");
|
| 1902 |
+
}
|
| 1903 |
+
|
| 1904 |
+
//FB::log("Loading link details via AJAX");
|
| 1905 |
+
|
| 1906 |
+
if ( isset($_GET['link_id']) ){
|
| 1907 |
+
//FB::info("Link ID found in GET");
|
| 1908 |
+
$link_id = intval($_GET['link_id']);
|
| 1909 |
+
} else if ( isset($_POST['link_id']) ){
|
| 1910 |
+
//FB::info("Link ID found in POST");
|
| 1911 |
+
$link_id = intval($_POST['link_id']);
|
| 1912 |
+
} else {
|
| 1913 |
+
//FB::error('Link ID not specified, you hacking bastard.');
|
| 1914 |
+
die('Error : link ID not specified');
|
| 1915 |
+
}
|
| 1916 |
+
|
| 1917 |
+
//Load the link. link_details_row needs it as an array, so
|
| 1918 |
+
//we'll have to do this the long way.
|
| 1919 |
+
$q = "SELECT
|
| 1920 |
+
links.*,
|
| 1921 |
+
COUNT(*) as instance_count
|
| 1922 |
+
|
| 1923 |
+
FROM
|
| 1924 |
+
{$wpdb->prefix}blc_links AS links,
|
| 1925 |
+
{$wpdb->prefix}blc_instances as instances
|
| 1926 |
+
|
| 1927 |
+
WHERE
|
| 1928 |
+
links.link_id = %d
|
| 1929 |
+
|
| 1930 |
+
GROUP BY links.link_id";
|
| 1931 |
+
|
| 1932 |
+
$link = $wpdb->get_row( $wpdb->prepare($q, $link_id), ARRAY_A );
|
| 1933 |
+
if ( is_array($link) ){
|
| 1934 |
+
//FB::info($link, 'Link loaded');
|
| 1935 |
+
$this->link_details_row($link);
|
| 1936 |
+
die();
|
| 1937 |
+
} else {
|
| 1938 |
+
die ("Failed to load link details (" . $wpdb->last_error . ")");
|
| 1939 |
+
}
|
| 1940 |
+
}
|
| 1941 |
+
|
| 1942 |
+
function ajax_exclude_link(){
|
| 1943 |
+
if ( !current_user_can('manage_options') ){
|
| 1944 |
+
die( json_encode( array(
|
| 1945 |
+
'error' => "You're not allowed to do that!"
|
| 1946 |
+
)));
|
| 1947 |
+
}
|
| 1948 |
+
|
| 1949 |
+
if ( isset($_POST['link_id']) ){
|
| 1950 |
+
//Load the link
|
| 1951 |
+
$link = new blcLink( intval($_POST['link_id']) );
|
| 1952 |
+
|
| 1953 |
+
if ( !$link->valid() ){
|
| 1954 |
+
die( json_encode( array(
|
| 1955 |
+
'error' => "Oops, I can't find the link ".intval($_POST['link_id'])
|
| 1956 |
+
)));
|
| 1957 |
+
}
|
| 1958 |
+
|
| 1959 |
+
//Add the URL to the exclusion list
|
| 1960 |
+
if ( !in_array( $link->url, $this->conf->options['exclusion_list'] ) ){
|
| 1961 |
+
$this->conf->options['exclusion_list'][] = $link->url;
|
| 1962 |
+
//Also mark it as already checked so that it doesn't show up with other broken links.
|
| 1963 |
+
//FB::info("The URL {$link->url} is excluded, marking link {$link->link_id} as already checked.");
|
| 1964 |
+
$link->last_check = date('Y-m-d H:i:s');
|
| 1965 |
+
$link->http_code = 200; //Use a fake code so that the link doesn't show up in queries looking for broken links.
|
| 1966 |
+
$link->timeout = false;
|
| 1967 |
+
$link->request_duration = 0;
|
| 1968 |
+
$link->log = "This link wasn't checked because a matching keyword was found on your exclusion list.";
|
| 1969 |
+
$link->save();
|
| 1970 |
+
}
|
| 1971 |
+
|
| 1972 |
+
$this->conf->save_options();
|
| 1973 |
+
|
| 1974 |
+
die( json_encode( array(
|
| 1975 |
+
'ok' => "URL {$link->url} added to the exclusion list"
|
| 1976 |
+
)));
|
| 1977 |
+
} else {
|
| 1978 |
+
die( json_encode( array(
|
| 1979 |
+
'error' => "Link ID not specified"
|
| 1980 |
+
)));
|
| 1981 |
+
}
|
| 1982 |
+
}
|
| 1983 |
+
|
| 1984 |
+
/**
|
| 1985 |
+
* ws_broken_link_checker::acquire_lock()
|
| 1986 |
+
* Create and lock a temporary file.
|
| 1987 |
+
*
|
| 1988 |
+
* @return bool
|
| 1989 |
+
*/
|
| 1990 |
+
function acquire_lock(){
|
| 1991 |
+
//Maybe we already have the lock?
|
| 1992 |
+
if ( $this->lockfile_handle ){
|
| 1993 |
+
return true;
|
| 1994 |
+
}
|
| 1995 |
+
|
| 1996 |
+
$fn = $this->lockfile_name();
|
| 1997 |
+
if ( $fn ){
|
| 1998 |
+
//Open the lockfile
|
| 1999 |
+
$this->lockfile_handle = fopen($fn, 'w+');
|
| 2000 |
+
if ( $this->lockfile_handle ){
|
| 2001 |
+
//Do an exclusive lock
|
| 2002 |
+
if (flock($this->lockfile_handle, LOCK_EX | LOCK_NB)) {
|
| 2003 |
+
//File locked successfully
|
| 2004 |
+
return true;
|
| 2005 |
+
} else {
|
| 2006 |
+
//Something went wrong
|
| 2007 |
+
fclose($this->lockfile_handle);
|
| 2008 |
+
$this->lockfile_handle = null;
|
| 2009 |
+
return false;
|
| 2010 |
+
}
|
| 2011 |
+
} else {
|
| 2012 |
+
//Can't open the file, fail.
|
| 2013 |
+
return false;
|
| 2014 |
+
}
|
| 2015 |
+
} else {
|
| 2016 |
+
//Uh oh, can't generate a lockfile name. This is bad.
|
| 2017 |
+
//FB::error("Can't find a writable directory to use for my lock file!");
|
| 2018 |
+
return false;
|
| 2019 |
+
};
|
| 2020 |
+
}
|
| 2021 |
+
|
| 2022 |
+
/**
|
| 2023 |
+
* ws_broken_link_checker::release_lock()
|
| 2024 |
+
* Unlock and delete the temporary file
|
| 2025 |
+
*
|
| 2026 |
+
* @return bool
|
| 2027 |
+
*/
|
| 2028 |
+
function release_lock(){
|
| 2029 |
+
if ( $this->lockfile_handle ){
|
| 2030 |
+
//Close the file (implicitly releasing the lock)
|
| 2031 |
+
fclose( $this->lockfile_handle );
|
| 2032 |
+
//Delete the file
|
| 2033 |
+
$fn = $this->lockfile_name();
|
| 2034 |
+
if ( file_exists( $fn ) ) {
|
| 2035 |
+
unlink( $fn );
|
| 2036 |
+
}
|
| 2037 |
+
$this->lockfile_handle = null;
|
| 2038 |
+
return true;
|
| 2039 |
+
} else {
|
| 2040 |
+
//We didn't have the lock anyway...
|
| 2041 |
+
return false;
|
| 2042 |
+
}
|
| 2043 |
+
}
|
| 2044 |
+
|
| 2045 |
+
/**
|
| 2046 |
+
* ws_broken_link_checker::lockfile_name()
|
| 2047 |
+
* Generate system-specific lockfile filename
|
| 2048 |
+
*
|
| 2049 |
+
* @return string A filename or FALSE on error
|
| 2050 |
+
*/
|
| 2051 |
+
function lockfile_name(){
|
| 2052 |
+
//Try to find the temp directory.
|
| 2053 |
+
$path = sys_get_temp_dir();
|
| 2054 |
+
if ( $path && is_writable($path)){
|
| 2055 |
+
return trailingslashit($path) . '/wp_blc_lock';
|
| 2056 |
+
} else {
|
| 2057 |
+
//Try the plugin's directory.
|
| 2058 |
+
if ( is_writable( dirname(__FILE__) ) ){
|
| 2059 |
+
return dirname(__FILE__) . '/wp_blc_lock';
|
| 2060 |
+
//Try the wp-content directory
|
| 2061 |
+
} else if ( is_writable( WP_CONTENT_DIR ) ){
|
| 2062 |
+
return WP_CONTENT_DIR . '/wp_blc_lock';
|
| 2063 |
+
} else {
|
| 2064 |
+
//Fail.
|
| 2065 |
+
return false;
|
| 2066 |
+
}
|
| 2067 |
+
}
|
| 2068 |
+
}
|
| 2069 |
+
|
| 2070 |
+
function hook_add_link( $link_id ){
|
| 2071 |
+
$this->mark_unsynched( $link_id, 'blogroll' );
|
| 2072 |
+
}
|
| 2073 |
+
|
| 2074 |
+
function hook_edit_link( $link_id ){
|
| 2075 |
+
$this->mark_unsynched( $link_id, 'blogroll' );
|
| 2076 |
+
}
|
| 2077 |
+
|
| 2078 |
+
function hook_delete_link( $link_id ){
|
| 2079 |
+
global $wpdb;
|
| 2080 |
+
//Delete the synch record
|
| 2081 |
+
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}blc_synch WHERE source_id = %d AND source_type='blogroll'", $link_id ) );
|
| 2082 |
+
|
| 2083 |
+
//Get the matching instance record.
|
| 2084 |
+
$inst = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}blc_instances WHERE source_id = %d AND source_type = 'blogroll'", $link_id), ARRAY_A );
|
| 2085 |
+
|
| 2086 |
+
if ( !$inst ) {
|
| 2087 |
+
//No instance record? No problem.
|
| 2088 |
+
return;
|
| 2089 |
+
}
|
| 2090 |
+
|
| 2091 |
+
//Remove it
|
| 2092 |
+
$wpdb->query( $wpdb->prepare("DELETE FROM {$wpdb->prefix}blc_instances WHERE instance_id = %d", $inst['instance_id']) );
|
| 2093 |
+
|
| 2094 |
+
//Remove the link that was associated with this instance if it has no more related instances.
|
| 2095 |
+
$this->cleanup_links( $inst['link_id'] );
|
| 2096 |
+
}
|
| 2097 |
+
|
| 2098 |
+
function hook_wp_dashboard_setup(){
|
| 2099 |
+
if ( function_exists( 'wp_add_dashboard_widget' ) ) {
|
| 2100 |
+
wp_add_dashboard_widget(
|
| 2101 |
+
'blc_dashboard_widget',
|
| 2102 |
+
'Broken Link Checker',
|
| 2103 |
+
array( &$this, 'dashboard_widget' ),
|
| 2104 |
+
array( &$this, 'dashboard_widget_control' )
|
| 2105 |
+
);
|
| 2106 |
+
}
|
| 2107 |
+
}
|
| 2108 |
+
|
| 2109 |
+
function lockfile_warning(){
|
| 2110 |
+
$my_dir = '/plugins/' . basename(dirname(__FILE__)) . '/';
|
| 2111 |
+
$settings_page = admin_url( 'options-general.php?page=link-checker-settings#lockfile_directory' );
|
| 2112 |
+
|
| 2113 |
+
echo sprintf('
|
| 2114 |
+
<div id="blc-lockfile-warning" class="error"><p>
|
| 2115 |
+
<strong>Broken Link Checker can\'t create a lockfile.</strong>
|
| 2116 |
+
Please make the directory <code>%s</code> writable by plugins.
|
| 2117 |
+
|
| 2118 |
+
<a href="javascript:void(0)" onclick="jQuery(\'#blc-lockfile-details\').toggle()">Details</a>
|
| 2119 |
+
</p>
|
| 2120 |
+
|
| 2121 |
+
<div id="blc-lockfile-details" style="display:none;"><p>
|
| 2122 |
+
The plugin uses a file-based locking mechanism to ensure that only one instance of the
|
| 2123 |
+
resource-heavy link checking algorithm is running at any given time. Unfortunately,
|
| 2124 |
+
BLC can\'t find a writable directory where it could store the lockfile - it failed to
|
| 2125 |
+
detect the location of your server\'s temporary directory, and the plugin\'s own directory
|
| 2126 |
+
isn\'t writable by PHP. To fix this problem, please make the plugin\'s directory writable.
|
| 2127 |
+
</p>
|
| 2128 |
+
</div>
|
| 2129 |
+
</div>',
|
| 2130 |
+
$my_dir, $settings_page);
|
| 2131 |
+
}
|
| 2132 |
+
|
| 2133 |
+
}//class ends here
|
| 2134 |
+
|
| 2135 |
+
} // if class_exists...
|
| 2136 |
+
|
| 2137 |
+
?>
|
highlighter-class.php
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* @author W-Shadow
|
| 5 |
+
* @copyright 2009
|
| 6 |
+
*
|
| 7 |
+
* @requires blcUtility
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
class blcLinkHighlighter {
|
| 11 |
+
|
| 12 |
+
var $links_to_remove;
|
| 13 |
+
var $broken_link_css;
|
| 14 |
+
var $current_permalink;
|
| 15 |
+
|
| 16 |
+
function blcLinkHighlighter( $broken_link_css = '' ) {
|
| 17 |
+
if ( !empty( $broken_link_css ) ){
|
| 18 |
+
$this->broken_link_css = $broken_link_css;
|
| 19 |
+
add_action( 'wp_head', array(&$this,'hook_wp_head') );
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
add_filter( 'the_content', array(&$this,'hook_the_content') );
|
| 23 |
+
$this->current_permalink = '';
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
function hook_the_content($content){
|
| 27 |
+
global $post, $wpdb;
|
| 28 |
+
if ( empty($post) ) return $content;
|
| 29 |
+
|
| 30 |
+
//Get the post permalink - it's used to resolve relative URLs
|
| 31 |
+
$this->current_permalink = get_permalink( $post->ID );
|
| 32 |
+
|
| 33 |
+
$q = "
|
| 34 |
+
SELECT instances.link_text, links.*
|
| 35 |
+
|
| 36 |
+
FROM {$wpdb->prefix}blc_instances AS instances, {$wpdb->prefix}blc_links AS links
|
| 37 |
+
|
| 38 |
+
WHERE
|
| 39 |
+
instances.source_id = %d
|
| 40 |
+
AND instances.source_type = 'post'
|
| 41 |
+
AND instances.instance_type = 'link'
|
| 42 |
+
|
| 43 |
+
AND instances.link_id = links.link_id
|
| 44 |
+
AND links.check_count > 0
|
| 45 |
+
AND ( links.http_code < 200 OR links.http_code >= 400 OR links.timeout = 1 )
|
| 46 |
+
AND links.http_code <> " . BLC_CHECKING;
|
| 47 |
+
|
| 48 |
+
$rows = $wpdb->get_results( $wpdb->prepare( $q, $post->ID ), ARRAY_A );
|
| 49 |
+
if( $rows ){
|
| 50 |
+
$this->links_to_remove = array();
|
| 51 |
+
foreach($rows as $row){
|
| 52 |
+
$this->links_to_remove[$row['url']] = $row;
|
| 53 |
+
}
|
| 54 |
+
$content = preg_replace_callback( blcUtility::link_pattern(), array(&$this,'mark_broken_links'), $content );
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
return $content;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
function mark_broken_links($matches){
|
| 61 |
+
//TODO: Tooltip-style popups with more info
|
| 62 |
+
$url = blcUtility::normalize_url( html_entity_decode( $matches[3], $this->current_permalink ) );
|
| 63 |
+
if( isset( $this->links_to_remove[$url] ) ){
|
| 64 |
+
return $matches[1].$matches[2].$matches[3].$matches[2].' class="broken_link" '.$matches[4].
|
| 65 |
+
$matches[5].$matches[6];
|
| 66 |
+
} else {
|
| 67 |
+
return $matches[0];
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
function hook_wp_head(){
|
| 72 |
+
echo '<style type="text/css">',$this->broken_link_css,'</style>';
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
?>
|
link-classes.php
CHANGED
|
@@ -96,17 +96,22 @@ class blcLink {
|
|
| 96 |
*/
|
| 97 |
function check(){
|
| 98 |
if ( !$this->valid() ) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
/*
|
| 100 |
Check for problematic (though not necessarily "broken") links.
|
| 101 |
If a link has been checked multiple times and still hasn't been marked as
|
| 102 |
timed-out or broken then probably the checking algorithm is having problems with
|
| 103 |
that link. Mark it as timed-out and hope the user sorts it out.
|
| 104 |
*/
|
| 105 |
-
if ( ($this->check_count >= 3) && ( !$this->timeout ) && (
|
| 106 |
-
$this->timeout =
|
|
|
|
| 107 |
$this->last_check = date('Y-m-d H:i:s');
|
| 108 |
$this->log .= "\r\n[A weird error was detected. This should never happen.]";
|
| 109 |
-
$this->save();
|
| 110 |
return false;
|
| 111 |
}
|
| 112 |
|
|
@@ -132,7 +137,8 @@ class blcLink {
|
|
| 132 |
$parts = parse_url($url);
|
| 133 |
//Only HTTP links are checked. All others are automatically considered okay.
|
| 134 |
if ( ($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') ) {
|
| 135 |
-
$this->log .= "URL protocol ($parts[scheme]) is not HTTP. This link won't be checked.\n";
|
|
|
|
| 136 |
return true;
|
| 137 |
}
|
| 138 |
|
|
@@ -174,12 +180,11 @@ class blcLink {
|
|
| 174 |
}
|
| 175 |
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
|
| 176 |
}
|
| 177 |
-
|
| 178 |
|
| 179 |
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
| 180 |
|
| 181 |
$nobody=false;
|
| 182 |
-
if($parts['scheme']=='https'){
|
| 183 |
//TODO: Redirects don't work with HTTPS
|
| 184 |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
| 185 |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
|
@@ -189,11 +194,8 @@ class blcLink {
|
|
| 189 |
//curl_setopt($ch, CURLOPT_RANGE, '0-1023');
|
| 190 |
}
|
| 191 |
|
| 192 |
-
//We definitely want headers.
|
| 193 |
curl_setopt($ch, CURLOPT_HEADER, true);
|
| 194 |
//register a callback function which will process the headers
|
| 195 |
-
//this assumes your code is into a class method, and uses $this->readHeader
|
| 196 |
-
//as the callback function.
|
| 197 |
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'read_header'));
|
| 198 |
|
| 199 |
//Execute the request
|
|
@@ -221,7 +223,7 @@ class blcLink {
|
|
| 221 |
$this->log .= $this->last_headers."\n";
|
| 222 |
}
|
| 223 |
|
| 224 |
-
$this->http_code = $code!=0 ? $code : BLC_TIMEOUT;
|
| 225 |
$this->final_url = $info['url'];
|
| 226 |
$this->request_duration = $info['total_time'];
|
| 227 |
$this->redirect_count = $info['redirect_count'];
|
| 96 |
*/
|
| 97 |
function check(){
|
| 98 |
if ( !$this->valid() ) return false;
|
| 99 |
+
|
| 100 |
+
//General note : there is usually no need to save() the result of the check
|
| 101 |
+
//in this method because it will be typically called from wsBrokenLinkChecker::work()
|
| 102 |
+
//that will call the save() method for us.
|
| 103 |
+
|
| 104 |
/*
|
| 105 |
Check for problematic (though not necessarily "broken") links.
|
| 106 |
If a link has been checked multiple times and still hasn't been marked as
|
| 107 |
timed-out or broken then probably the checking algorithm is having problems with
|
| 108 |
that link. Mark it as timed-out and hope the user sorts it out.
|
| 109 |
*/
|
| 110 |
+
if ( ($this->check_count >= 3) && ( !$this->timeout ) && ( $this->http_code == BLC_CHECKING ) ) {
|
| 111 |
+
$this->timeout = true;
|
| 112 |
+
$this->http_code = BLC_TIMEOUT;
|
| 113 |
$this->last_check = date('Y-m-d H:i:s');
|
| 114 |
$this->log .= "\r\n[A weird error was detected. This should never happen.]";
|
|
|
|
| 115 |
return false;
|
| 116 |
}
|
| 117 |
|
| 137 |
$parts = parse_url($url);
|
| 138 |
//Only HTTP links are checked. All others are automatically considered okay.
|
| 139 |
if ( ($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') ) {
|
| 140 |
+
$this->log .= "URL protocol ($parts[scheme]) is not HTTP(S). This link won't be checked.\n";
|
| 141 |
+
$this->http_code = 200;
|
| 142 |
return true;
|
| 143 |
}
|
| 144 |
|
| 180 |
}
|
| 181 |
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
|
| 182 |
}
|
|
|
|
| 183 |
|
| 184 |
curl_setopt($ch, CURLOPT_FAILONERROR, false);
|
| 185 |
|
| 186 |
$nobody=false;
|
| 187 |
+
if( $parts['scheme'] == 'https' ){
|
| 188 |
//TODO: Redirects don't work with HTTPS
|
| 189 |
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
| 190 |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
| 194 |
//curl_setopt($ch, CURLOPT_RANGE, '0-1023');
|
| 195 |
}
|
| 196 |
|
|
|
|
| 197 |
curl_setopt($ch, CURLOPT_HEADER, true);
|
| 198 |
//register a callback function which will process the headers
|
|
|
|
|
|
|
| 199 |
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'read_header'));
|
| 200 |
|
| 201 |
//Execute the request
|
| 223 |
$this->log .= $this->last_headers."\n";
|
| 224 |
}
|
| 225 |
|
| 226 |
+
$this->http_code = $code != 0 ? $code : BLC_TIMEOUT;
|
| 227 |
$this->final_url = $info['url'];
|
| 228 |
$this->request_duration = $info['total_time'];
|
| 229 |
$this->redirect_count = $info['redirect_count'];
|
readme.txt
CHANGED
|
@@ -3,7 +3,7 @@ Contributors: whiteshadow
|
|
| 3 |
Tags: links, broken, maintenance, blogroll, custom fields, admin
|
| 4 |
Requires at least: 2.7.0
|
| 5 |
Tested up to: 2.9
|
| 6 |
-
Stable tag: 0.5.
|
| 7 |
|
| 8 |
This plugin will check your posts, custom fields and the blogroll for broken links and missing images and notify you if any are found.
|
| 9 |
|
|
@@ -58,6 +58,15 @@ To upgrade your installation
|
|
| 58 |
|
| 59 |
== Changelog ==
|
| 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
= 0.5.8.1 =
|
| 62 |
* Added partial proxy support when CURL is available. Proxies will be fully supported in a later version.
|
| 63 |
|
|
@@ -72,6 +81,7 @@ To upgrade your installation
|
|
| 72 |
* Improved relative URL parsing. The plugin now uses the permalink as the base URL when processing posts.
|
| 73 |
|
| 74 |
= 0.5.5 =
|
|
|
|
| 75 |
* URLs with spaces (and some other special characters) are now handled better and won't get marked as "broken" all the time.
|
| 76 |
* Links that contain quote characters are parsed properly.
|
| 77 |
|
|
@@ -92,7 +102,8 @@ To upgrade your installation
|
|
| 92 |
* Fix a bug when the plugin creates a DB table with the wrong prefix.
|
| 93 |
|
| 94 |
= 0.5 =
|
| 95 |
-
* This is a near-complete rewrite with a lot of new features.
|
|
|
|
| 96 |
|
| 97 |
= 0.4.14 =
|
| 98 |
* Fix false positives when the URL contains an #anchor
|
|
@@ -125,8 +136,10 @@ To upgrade your installation
|
|
| 125 |
* New and improved (TM) regexps for finding links and images.
|
| 126 |
* A "Settings" link added to plugin's action links.
|
| 127 |
* And probably other stuff I forgot!
|
|
|
|
| 128 |
|
| 129 |
= 0.4.7 =
|
|
|
|
| 130 |
* Autoselect link URL after the user clicks "Edit".
|
| 131 |
* Make sure only HTTP and HTTPS links are checked.
|
| 132 |
* More substantive improvements will hopefully follow next week.
|
|
@@ -135,6 +148,7 @@ To upgrade your installation
|
|
| 135 |
* Minor compatibility enhancement in wsblc\_ajax.php - don't load wpdb if it's already loaded.
|
| 136 |
|
| 137 |
= 0.4.5 =
|
|
|
|
| 138 |
* Revisions don't get added to the work queue anymore.
|
| 139 |
* Workaround for rare cURL timeout bug.
|
| 140 |
* Improved WP 2.6 compatibility.
|
|
@@ -214,3 +228,4 @@ To upgrade your installation
|
|
| 214 |
|
| 215 |
= 0.1 =
|
| 216 |
* *There are no release notes for this version*
|
|
|
| 3 |
Tags: links, broken, maintenance, blogroll, custom fields, admin
|
| 4 |
Requires at least: 2.7.0
|
| 5 |
Tested up to: 2.9
|
| 6 |
+
Stable tag: 0.5.10
|
| 7 |
|
| 8 |
This plugin will check your posts, custom fields and the blogroll for broken links and missing images and notify you if any are found.
|
| 9 |
|
| 58 |
|
| 59 |
== Changelog ==
|
| 60 |
|
| 61 |
+
*This is an automatically generated changelog*
|
| 62 |
+
|
| 63 |
+
= 0.5.9 =
|
| 64 |
+
* Added an autogenerated changelog.
|
| 65 |
+
* Added a workaround to make this plugin compatible with the SimplePress forum.
|
| 66 |
+
* Fixed <pre> block parsing, again.
|
| 67 |
+
* Fixed a bug where URLs that only differ in character case would be treated as equivalent.
|
| 68 |
+
* Improved the database upgrade routine.
|
| 69 |
+
|
| 70 |
= 0.5.8.1 =
|
| 71 |
* Added partial proxy support when CURL is available. Proxies will be fully supported in a later version.
|
| 72 |
|
| 81 |
* Improved relative URL parsing. The plugin now uses the permalink as the base URL when processing posts.
|
| 82 |
|
| 83 |
= 0.5.5 =
|
| 84 |
+
* Minor bugfixes
|
| 85 |
* URLs with spaces (and some other special characters) are now handled better and won't get marked as "broken" all the time.
|
| 86 |
* Links that contain quote characters are parsed properly.
|
| 87 |
|
| 102 |
* Fix a bug when the plugin creates a DB table with the wrong prefix.
|
| 103 |
|
| 104 |
= 0.5 =
|
| 105 |
+
* This is a near-complete rewrite with a lot of new features.
|
| 106 |
+
* See �http://w-shadow.com/blog/2009/05/22/broken-link-checker-05/ for details.
|
| 107 |
|
| 108 |
= 0.4.14 =
|
| 109 |
* Fix false positives when the URL contains an #anchor
|
| 136 |
* New and improved (TM) regexps for finding links and images.
|
| 137 |
* A "Settings" link added to plugin's action links.
|
| 138 |
* And probably other stuff I forgot!
|
| 139 |
+
* Grr :P
|
| 140 |
|
| 141 |
= 0.4.7 =
|
| 142 |
+
* Minor enhancements :
|
| 143 |
* Autoselect link URL after the user clicks "Edit".
|
| 144 |
* Make sure only HTTP and HTTPS links are checked.
|
| 145 |
* More substantive improvements will hopefully follow next week.
|
| 148 |
* Minor compatibility enhancement in wsblc\_ajax.php - don't load wpdb if it's already loaded.
|
| 149 |
|
| 150 |
= 0.4.5 =
|
| 151 |
+
* Bugfixes. Nothing more, nothing less.
|
| 152 |
* Revisions don't get added to the work queue anymore.
|
| 153 |
* Workaround for rare cURL timeout bug.
|
| 154 |
* Improved WP 2.6 compatibility.
|
| 228 |
|
| 229 |
= 0.1 =
|
| 230 |
* *There are no release notes for this version*
|
| 231 |
+
|
utility-class.php
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
*/
|
| 7 |
|
| 8 |
|
| 9 |
-
if (is_admin() && !function_exists('json_encode')){
|
| 10 |
//Load JSON functions for PHP < 5.2
|
| 11 |
if (!class_exists('Services_JSON')){
|
| 12 |
require 'JSON.php';
|
|
@@ -19,20 +19,33 @@ if (is_admin() && !function_exists('json_encode')){
|
|
| 19 |
}
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
if ( !class_exists('blcUtility') ){
|
| 23 |
|
| 24 |
class blcUtility {
|
| 25 |
|
| 26 |
//A regxp for images
|
| 27 |
function img_pattern(){
|
| 28 |
-
// \1 \2
|
| 29 |
-
return '/(<img[\s]+[^>]*src\s*=\s*)([\"\'])([
|
| 30 |
}
|
| 31 |
|
| 32 |
//A regexp for links
|
| 33 |
function link_pattern(){
|
| 34 |
-
// \1 \2 \3 URL
|
| 35 |
-
return '/(<a[\s]+[^>]*href\s*=\s*)([\"\'])([
|
| 36 |
}
|
| 37 |
|
| 38 |
/**
|
|
@@ -43,8 +56,11 @@ class blcUtility {
|
|
| 43 |
* @return string A normalized URL or FALSE if the URL is invalid
|
| 44 |
*/
|
| 45 |
function normalize_url($url, $base_url = ''){
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
if(isset($parts['scheme'])) {
|
| 50 |
//Only HTTP(S) links are checked. Other protocols are not supported.
|
|
@@ -54,17 +70,17 @@ class blcUtility {
|
|
| 54 |
|
| 55 |
$url = html_entity_decode($url);
|
| 56 |
$url = preg_replace(
|
| 57 |
-
array('/([\?&]PHPSESSID=\w+)$/i',
|
| 58 |
-
'/(#[^\/]*)$/',
|
| 59 |
-
'/&/',
|
| 60 |
-
'/^(javascript:.*)/i',
|
| 61 |
-
'/([\?&]sid=\w+)$/i'
|
| 62 |
),
|
| 63 |
array('','','&','',''),
|
| 64 |
$url);
|
| 65 |
-
$url=trim($url);
|
| 66 |
|
| 67 |
-
if($url=='') return false;
|
| 68 |
|
| 69 |
// turn relative URLs into absolute URLs
|
| 70 |
if ( empty($base_url) ) $base_url = get_option('siteurl');
|
|
@@ -86,7 +102,7 @@ class blcUtility {
|
|
| 86 |
//WTF? $relative is a seriously malformed URL
|
| 87 |
return false;
|
| 88 |
}
|
| 89 |
-
if(isset($p["scheme"])) return $relative;
|
| 90 |
|
| 91 |
$parts=(parse_url($absolute));
|
| 92 |
|
| 6 |
*/
|
| 7 |
|
| 8 |
|
| 9 |
+
if ( is_admin() && !function_exists('json_encode') ){
|
| 10 |
//Load JSON functions for PHP < 5.2
|
| 11 |
if (!class_exists('Services_JSON')){
|
| 12 |
require 'JSON.php';
|
| 19 |
}
|
| 20 |
}
|
| 21 |
|
| 22 |
+
if ( !function_exists('sys_get_temp_dir')) {
|
| 23 |
+
function sys_get_temp_dir() {
|
| 24 |
+
if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
|
| 25 |
+
if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
|
| 26 |
+
if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
|
| 27 |
+
$tempfile=tempnam(uniqid(rand(),TRUE),'');
|
| 28 |
+
if (file_exists($tempfile)) {
|
| 29 |
+
unlink($tempfile);
|
| 30 |
+
return realpath(dirname($tempfile));
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
if ( !class_exists('blcUtility') ){
|
| 36 |
|
| 37 |
class blcUtility {
|
| 38 |
|
| 39 |
//A regxp for images
|
| 40 |
function img_pattern(){
|
| 41 |
+
// \1 \2 \3 URL \4
|
| 42 |
+
return '/(<img[\s]+[^>]*src\s*=\s*)([\"\'])([^>]+?)\2([^<>]*>)/i';
|
| 43 |
}
|
| 44 |
|
| 45 |
//A regexp for links
|
| 46 |
function link_pattern(){
|
| 47 |
+
// \1 \2 \3 URL \4 \5 Text \6
|
| 48 |
+
return '/(<a[\s]+[^>]*href\s*=\s*)([\"\'])([^>]+?)\2([^<>]*>)((?sU).*)(<\/a>)/i';
|
| 49 |
}
|
| 50 |
|
| 51 |
/**
|
| 56 |
* @return string A normalized URL or FALSE if the URL is invalid
|
| 57 |
*/
|
| 58 |
function normalize_url($url, $base_url = ''){
|
| 59 |
+
//Sometimes links may contain shortcodes. Parse them.
|
| 60 |
+
$url = do_shortcode($url);
|
| 61 |
+
|
| 62 |
+
$parts = @parse_url($url);
|
| 63 |
+
if(!$parts) return false; //Invalid URL
|
| 64 |
|
| 65 |
if(isset($parts['scheme'])) {
|
| 66 |
//Only HTTP(S) links are checked. Other protocols are not supported.
|
| 70 |
|
| 71 |
$url = html_entity_decode($url);
|
| 72 |
$url = preg_replace(
|
| 73 |
+
array('/([\?&]PHPSESSID=\w+)$/i', //remove session ID
|
| 74 |
+
'/(#[^\/]*)$/', //and anchors/fragments
|
| 75 |
+
'/&/', //convert improper HTML entities
|
| 76 |
+
'/^(javascript:.*)/i', //treat links that contain JS as links with an empty URL
|
| 77 |
+
'/([\?&]sid=\w+)$/i' //remove another flavour of session ID
|
| 78 |
),
|
| 79 |
array('','','&','',''),
|
| 80 |
$url);
|
| 81 |
+
$url = trim($url);
|
| 82 |
|
| 83 |
+
if ( $url=='' ) return false;
|
| 84 |
|
| 85 |
// turn relative URLs into absolute URLs
|
| 86 |
if ( empty($base_url) ) $base_url = get_option('siteurl');
|
| 102 |
//WTF? $relative is a seriously malformed URL
|
| 103 |
return false;
|
| 104 |
}
|
| 105 |
+
if( isset($p["scheme"]) ) return $relative;
|
| 106 |
|
| 107 |
$parts=(parse_url($absolute));
|
| 108 |
|
