Broken Link Checker - Version 0.5.14

Version Description

  • Made the timeout value used when checking links user-configurable.
  • The plugin will now report an error instead of failing silently when it can't create the necessary database tables.
  • Added a table listing assorted debug info to the settings page. Click the small "Show debug info" link to display it.
  • Cleaned up some redundant/useless code.
Download this release

Release Info

Developer whiteshadow
Plugin Icon 128x128 Broken Link Checker
Version 0.5.14
Comparing to
See all releases

Code changes from version 0.5.13 to 0.5.14

broken-link-checker.php CHANGED
@@ -4,7 +4,7 @@
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.13
8
  Author: Janis Elsts
9
  Author URI: http://w-shadow.com/blog/
10
  */
@@ -14,10 +14,12 @@ Created by Janis Elsts (email : whiteshadow@w-shadow.com)
14
  MySQL 4.0 compatibility by Jeroen (www.yukka.eu)
15
  */
16
 
 
 
17
  /*
18
  //FirePHP for debugging
19
  if ( !class_exists('FB') ) {
20
- require 'FirePHPCore/fb.php';
21
  }
22
  //FB::setEnabled(false);
23
 
@@ -70,7 +72,9 @@ $blc_config_manager = new blcConfigurationManager(
70
 
71
  'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
72
  //If this option is not set, the plugin's own directory or the
73
- //system-wide /tmp directory will be used instead.
 
 
74
  )
75
  );
76
 
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.14
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
+ define('BLC_DEBUG', false);
18
+
19
  /*
20
  //FirePHP for debugging
21
  if ( !class_exists('FB') ) {
22
+ require_once 'FirePHPCore/fb.php4';
23
  }
24
  //FB::setEnabled(false);
25
 
72
 
73
  'custom_tmp_dir' => '', //The lockfile will be stored in this directory.
74
  //If this option is not set, the plugin's own directory or the
75
+ //system-wide /tmp directory will be used instead.
76
+
77
+ 'timeout' => 30, //Links that take longer than this to respond will be treated as broken.
78
  )
79
  );
80
 
config-manager.php CHANGED
@@ -5,6 +5,8 @@
5
  * @copyright 2009
6
  */
7
 
 
 
8
  class blcConfigurationManager {
9
 
10
  var $option_name;
@@ -82,4 +84,5 @@ class blcConfigurationManager {
82
  }
83
  }
84
 
 
85
  ?>
5
  * @copyright 2009
6
  */
7
 
8
+ if ( !class_exists('blcConfigurationManager') ){
9
+
10
  class blcConfigurationManager {
11
 
12
  var $option_name;
84
  }
85
  }
86
 
87
+ }
88
  ?>
core.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  //The plugin will use Snoopy in case CURL is not available
4
  //TODO: Use WP_HTTP instead of Snoopy
5
- if (!class_exists('Snoopy')) require_once(ABSPATH.'/wp-includes/class-snoopy.php');
6
 
7
  /**
8
  * Simple function to replicate PHP 5 behaviour
@@ -15,7 +15,7 @@ if ( !function_exists( 'microtime_float' ) ) {
15
  }
16
  }
17
 
18
- if (!class_exists('ws_broken_link_checker')) {
19
 
20
  class wsBrokenLinkChecker {
21
  var $conf;
@@ -56,7 +56,7 @@ class wsBrokenLinkChecker {
56
  add_action('edit_link', array(&$this,'hook_edit_link'));
57
  add_action('delete_link', array(&$this,'hook_delete_link'));
58
 
59
- //Load jQuery on Dashboard pages (possibly redundant as WP already does that)
60
  add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
61
 
62
  //The dashboard widget
@@ -314,9 +314,10 @@ class wsBrokenLinkChecker {
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?
@@ -330,9 +331,9 @@ class wsBrokenLinkChecker {
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,
@@ -352,8 +353,8 @@ class wsBrokenLinkChecker {
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)
@@ -361,8 +362,8 @@ class wsBrokenLinkChecker {
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.
@@ -379,8 +380,8 @@ class wsBrokenLinkChecker {
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
  //....
@@ -393,8 +394,8 @@ class wsBrokenLinkChecker {
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;
@@ -416,8 +417,11 @@ class wsBrokenLinkChecker {
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
 
@@ -452,11 +456,13 @@ class wsBrokenLinkChecker {
452
  if(isset($_POST['submit'])) {
453
  check_admin_referer('link-checker-options');
454
 
 
455
  $new_execution_time = intval($_POST['max_execution_time']);
456
  if( $new_execution_time > 0 ){
457
  $this->conf->options['max_execution_time'] = $new_execution_time;
458
  }
459
 
 
460
  $new_check_threshold=intval($_POST['check_threshold']);
461
  if( $new_check_threshold > 0 ){
462
  $this->conf->options['check_threshold'] = $new_check_threshold;
@@ -466,17 +472,34 @@ class wsBrokenLinkChecker {
466
  $new_broken_link_css = trim($_POST['broken_link_css']);
467
  $this->conf->options['broken_link_css'] = $new_broken_link_css;
468
 
469
- $this->conf->options['exclusion_list']=array_filter( preg_split( '/[\s\r\n]+/',
470
- $_POST['exclusion_list'], -1, PREG_SPLIT_NO_EMPTY ) );
471
- //TODO: Maybe update affected links when exclusion list changes (expensive).
 
 
 
 
 
 
472
 
473
- $new_custom_fields = array_filter( preg_split( '/[\s\r\n]+/',
474
- $_POST['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY ) );
 
 
 
 
475
  $diff1 = array_diff( $new_custom_fields, $this->conf->options['custom_fields'] );
476
  $diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields );
477
  $this->conf->options['custom_fields'] = $new_custom_fields;
478
 
 
479
  $this->conf->options['custom_tmp_dir'] = trim(stripslashes(strval($_POST['custom_tmp_dir'])));
 
 
 
 
 
 
480
 
481
  $this->conf->save_options();
482
 
@@ -492,8 +515,11 @@ class wsBrokenLinkChecker {
492
  $base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
493
  wp_redirect( add_query_arg( array( 'updated' => 1), $base_url ) );
494
  }
 
 
 
 
495
 
496
- ?>
497
  <div class="wrap"><h2>Broken Link Checker Options</h2>
498
 
499
  <form name="link_checker_options" method="post" action="<?php
@@ -506,7 +532,11 @@ class wsBrokenLinkChecker {
506
  <table class="form-table">
507
 
508
  <tr valign="top">
509
- <th scope="row">Status</th>
 
 
 
 
510
  <td>
511
 
512
 
@@ -539,6 +569,23 @@ class wsBrokenLinkChecker {
539
  </script>
540
  <?php //JHS: Recheck all posts link: ?>
541
  <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&amp;recheck=true')" /></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  </td>
543
  </tr>
544
 
@@ -547,7 +594,7 @@ class wsBrokenLinkChecker {
547
  <td>
548
 
549
  Every <input type="text" name="check_threshold" id="check_threshold"
550
- value="<?php echo $this->conf->options['check_threshold']; ?>" size='5' maxlength='3'/>
551
  hours
552
  <br/>
553
  <span class="description">
@@ -596,9 +643,31 @@ class wsBrokenLinkChecker {
596
  </td>
597
  </tr>
598
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  <tr valign="top">
600
  <th scope="row">
601
- <a name='lockfile_directory'></a>Custom temporary directory (advanced)</th>
602
  <td>
603
 
604
  <input type="text" name="custom_tmp_dir" id="custom_tmp_dir"
@@ -627,11 +696,11 @@ class wsBrokenLinkChecker {
627
  </tr>
628
 
629
  <tr valign="top">
630
- <th scope="row">Max. execution time (advanced)</th>
631
  <td>
632
 
633
  <input type="text" name="max_execution_time" id="max_execution_time"
634
- value="<?php echo $this->conf->options['max_execution_time']; ?>" size='5' maxlength='3'/>
635
  seconds
636
  <br/><span class="description">
637
  The plugin works by periodically creating a background worker instance that parses your posts looking for links,
@@ -641,14 +710,77 @@ class wsBrokenLinkChecker {
641
 
642
  </td>
643
  </tr>
644
-
645
  </table>
646
-
647
  <p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
648
  </form>
649
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  <?php
651
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652
 
653
  function links_page(){
654
  global $wpdb;
@@ -1659,7 +1791,7 @@ jQuery(function($){
1659
  if ( !$this->is_excluded( $link['url'] ) ) {
1660
  //Yes, do it
1661
  //FB::log("Checking link {$link[link_id]}");
1662
- $link_obj->check();
1663
  $link_obj->save();
1664
  } else {
1665
  //Nope, mark it as already checked.
@@ -2168,6 +2300,124 @@ jQuery(function($){
2168
  </div>',
2169
  $action_notice);
2170
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2171
 
2172
  }//class ends here
2173
 
2
 
3
  //The plugin will use Snoopy in case CURL is not available
4
  //TODO: Use WP_HTTP instead of Snoopy
5
+ if (!class_exists('Snoopy')) require_once(ABSPATH. WPINC . '/class-snoopy.php');
6
 
7
  /**
8
  * Simple function to replicate PHP 5 behaviour
15
  }
16
  }
17
 
18
+ if (!class_exists('wsBrokenLinkChecker')) {
19
 
20
  class wsBrokenLinkChecker {
21
  var $conf;
56
  add_action('edit_link', array(&$this,'hook_edit_link'));
57
  add_action('delete_link', array(&$this,'hook_delete_link'));
58
 
59
+ //Load jQuery on Dashboard pages (probably redundant as WP already does that)
60
  add_action('admin_print_scripts', array(&$this,'admin_print_scripts'));
61
 
62
  //The dashboard widget
314
  * ws_broken_link_checker::upgrade_database()
315
  * Create and/or upgrade database tables
316
  *
317
+ * @param bool $die_on_error Whether the function should stop the script and display an error message if a DB error is encountered.
318
  * @return void
319
  */
320
+ function upgrade_database( $die_on_error = true ){
321
  global $wpdb;
322
 
323
  //Do we need to upgrade?
331
  return false;
332
  }
333
 
334
+ //require_once (ABSPATH . 'wp-admin/includes/upgrade.php');
335
 
336
+ //Create the link table if it doesn't exist yet.
337
  $q = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}blc_links (
338
  link_id int(20) unsigned NOT NULL auto_increment,
339
  url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
353
  KEY timeout (timeout)
354
  )";
355
  if ( $wpdb->query( $q ) === false ){
356
+ if ( $die_on_error )
357
+ die('Database error : ' . $wpdb->last_error);
358
  };
359
 
360
  //Fix URL fields so that they are collated as case-sensitive (this can't be done via dbDelta)
362
  MODIFY url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL,
363
  MODIFY final_url text CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL";
364
  if ( $wpdb->query( $q ) === false ){
365
+ if ( $die_on_error )
366
+ die('Database error : ' . $wpdb->last_error);
367
  };
368
 
369
  //Create the instance table if it doesn't exist yet.
380
  KEY source_id (source_id,source_type)
381
  )";
382
  if ( $wpdb->query( $q ) === false ){
383
+ if ( $die_on_error )
384
+ die('Database error : ' . $wpdb->last_error);
385
  };
386
 
387
  //....
394
  KEY synched (synched)
395
  )";
396
  if ( $wpdb->query( $q ) === false ){
397
+ if ( $die_on_error )
398
+ die('Database error : ' . $wpdb->last_error);
399
  };
400
 
401
  $this->conf->options['current_db_version'] = $this->db_version;
417
  }
418
 
419
  function admin_menu(){
420
+ $options_page_hook = add_options_page('Link Checker Settings', 'Link Checker', 'manage_options',
421
  'link-checker-settings',array(&$this, 'options_page'));
422
+ //Add the hook that will add the plugin's CSS styles to it's settings page
423
+ add_action( 'admin_print_styles-' . $options_page_hook, array(&$this, 'options_page_css') );
424
+
425
  if (current_user_can('manage_options'))
426
  add_filter('plugin_action_links', array(&$this, 'plugin_action_links'), 10, 2);
427
 
456
  if(isset($_POST['submit'])) {
457
  check_admin_referer('link-checker-options');
458
 
459
+ //The execution time limit must be above zero
460
  $new_execution_time = intval($_POST['max_execution_time']);
461
  if( $new_execution_time > 0 ){
462
  $this->conf->options['max_execution_time'] = $new_execution_time;
463
  }
464
 
465
+ //The check threshold also must be > 0
466
  $new_check_threshold=intval($_POST['check_threshold']);
467
  if( $new_check_threshold > 0 ){
468
  $this->conf->options['check_threshold'] = $new_check_threshold;
472
  $new_broken_link_css = trim($_POST['broken_link_css']);
473
  $this->conf->options['broken_link_css'] = $new_broken_link_css;
474
 
475
+ //TODO: Maybe update affected links when exclusion list changes (could be expensive resource-wise).
476
+ $this->conf->options['exclusion_list'] = array_filter(
477
+ preg_split(
478
+ '/[\s\r\n]+/', //split on newlines and whitespace
479
+ $_POST['exclusion_list'],
480
+ -1,
481
+ PREG_SPLIT_NO_EMPTY //skip empty values
482
+ )
483
+ );
484
 
485
+ //Parse the custom field list
486
+ $new_custom_fields = array_filter(
487
+ preg_split( '/[\s\r\n]+/', $_POST['blc_custom_fields'], -1, PREG_SPLIT_NO_EMPTY )
488
+ );
489
+
490
+ //Calculate the difference between the old custom field list and the new one (used later)
491
  $diff1 = array_diff( $new_custom_fields, $this->conf->options['custom_fields'] );
492
  $diff2 = array_diff( $this->conf->options['custom_fields'], $new_custom_fields );
493
  $this->conf->options['custom_fields'] = $new_custom_fields;
494
 
495
+ //Temporary file directory
496
  $this->conf->options['custom_tmp_dir'] = trim(stripslashes(strval($_POST['custom_tmp_dir'])));
497
+
498
+ //HTTP timeout
499
+ $new_timeout = intval($_POST['timeout']);
500
+ if( $new_timeout > 0 ){
501
+ $this->conf->options['timeout'] = $new_timeout ;
502
+ }
503
 
504
  $this->conf->save_options();
505
 
515
  $base_url = remove_query_arg( array('_wpnonce', 'noheader', 'updated', 'error', 'action', 'message') );
516
  wp_redirect( add_query_arg( array( 'updated' => 1), $base_url ) );
517
  }
518
+
519
+ $debug = $this->get_debug_info();
520
+
521
+ ?>
522
 
 
523
  <div class="wrap"><h2>Broken Link Checker Options</h2>
524
 
525
  <form name="link_checker_options" method="post" action="<?php
532
  <table class="form-table">
533
 
534
  <tr valign="top">
535
+ <th scope="row">
536
+ Status
537
+ <br>
538
+ <a href="javascript:void(0)" id="blc-debug-info-toggle">Show debug info</a>
539
+ </th>
540
  <td>
541
 
542
 
569
  </script>
570
  <?php //JHS: Recheck all posts link: ?>
571
  <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&amp;recheck=true')" /></p>
572
+
573
+ <table id="blc-debug-info">
574
+ <?php
575
+
576
+ //Output the debug info in a table
577
+ foreach( $debug as $key => $value ){
578
+ printf (
579
+ '<tr valign="top" class="blc-debug-item-%s"><th scope="row">%s</th><td>%s<div class="blc-debug-message">%s</div></td></tr>',
580
+ $value['state'],
581
+ $key,
582
+ $value['value'],
583
+ ( array_key_exists('message', $value)?$value['message']:'')
584
+ );
585
+ }
586
+ ?>
587
+ </table>
588
+
589
  </td>
590
  </tr>
591
 
594
  <td>
595
 
596
  Every <input type="text" name="check_threshold" id="check_threshold"
597
+ value="<?php echo $this->conf->options['check_threshold']; ?>" size='5' maxlength='5'/>
598
  hours
599
  <br/>
600
  <span class="description">
643
  </td>
644
  </tr>
645
 
646
+ </table>
647
+
648
+ <h3>Advanced</h3>
649
+
650
+ <table class="form-table">
651
+
652
+
653
+ <tr valign="top">
654
+ <th scope="row">Timeout</th>
655
+ <td>
656
+
657
+ <input type="text" name="timeout" id="blc_timeout"
658
+ value="<?php echo $this->conf->options['timeout']; ?>" size='5' maxlength='3'/>
659
+ seconds
660
+ <br/><span class="description">
661
+ Links that take longer than this to load will be marked as broken.
662
+ </span>
663
+
664
+ </td>
665
+ </tr>
666
+
667
+
668
  <tr valign="top">
669
  <th scope="row">
670
+ <a name='lockfile_directory'></a>Custom temporary directory</th>
671
  <td>
672
 
673
  <input type="text" name="custom_tmp_dir" id="custom_tmp_dir"
696
  </tr>
697
 
698
  <tr valign="top">
699
+ <th scope="row">Max. execution time</th>
700
  <td>
701
 
702
  <input type="text" name="max_execution_time" id="max_execution_time"
703
+ value="<?php echo $this->conf->options['max_execution_time']; ?>" size='5' maxlength='5'/>
704
  seconds
705
  <br/><span class="description">
706
  The plugin works by periodically creating a background worker instance that parses your posts looking for links,
710
 
711
  </td>
712
  </tr>
713
+
714
  </table>
715
+
716
  <p class="submit"><input type="submit" name="submit" class='button-primary' value="<?php _e('Save Changes') ?>" /></p>
717
  </form>
718
  </div>
719
+
720
+ <script type='text/javascript'>
721
+ jQuery(function($){
722
+ var toggleButton = $('#blc-debug-info-toggle');
723
+
724
+ toggleButton.click(function(){
725
+
726
+ var box = $('#blc-debug-info');
727
+ box.toggle();
728
+ if( box.is(':visible') ){
729
+ toggleButton.text('Hide debug info');
730
+ } else {
731
+ toggleButton.text('Show debug info');
732
+ }
733
+
734
+ });
735
+ });
736
+ </script>
737
  <?php
738
  }
739
+
740
+ function options_page_css(){
741
+ ?>
742
+ <style type='text/css'>
743
+ #blc-debug-info-toggle {
744
+ font-size: smaller;
745
+ }
746
+
747
+ .blc-debug-item-ok {
748
+ background-color: #d7ffa2;
749
+ }
750
+ .blc-debug-item-warning {
751
+ background-color: #fcffa2;
752
+ }
753
+ .blc-debug-item-error {
754
+ background-color: #ffc4c4;
755
+ }
756
+
757
+ #blc-debug-info {
758
+ display: none;
759
+
760
+ text-align: left;
761
+
762
+ border-width: 1px;
763
+ border-color: gray;
764
+ border-style: solid;
765
+
766
+ border-spacing: 0px;
767
+ border-collapse: collapse;
768
+ }
769
+
770
+ #blc-debug-info th, #blc-debug-info td {
771
+ padding: 6px;
772
+ font-weight: normal;
773
+ text-shadow: none;
774
+
775
+ border-width: 1px ;
776
+ border-color: silver;
777
+ border-style: solid;
778
+
779
+ border-collapse: collapse;
780
+ }
781
+ </style>
782
+ <?php
783
+ }
784
 
785
  function links_page(){
786
  global $wpdb;
1791
  if ( !$this->is_excluded( $link['url'] ) ) {
1792
  //Yes, do it
1793
  //FB::log("Checking link {$link[link_id]}");
1794
+ $link_obj->check( $this->conf->options['timeout'] );
1795
  $link_obj->save();
1796
  } else {
1797
  //Nope, mark it as already checked.
2300
  </div>',
2301
  $action_notice);
2302
  }
2303
+
2304
+ /**
2305
+ * wsBrokenLinkChecker::get_debug_info()
2306
+ * Collect various debugging information and return it in an associative array
2307
+ *
2308
+ * @return array
2309
+ */
2310
+ function get_debug_info(){
2311
+ global $wpdb;
2312
+
2313
+ //Collect some information that's useful for debugging
2314
+ $debug = array();
2315
+
2316
+ //PHP version. Any one is fine as long as WP supports it.
2317
+ $debug['PHP version'] = array(
2318
+ 'state' => 'ok',
2319
+ 'value' => phpversion(),
2320
+ );
2321
+
2322
+ //MySQL version
2323
+ $debug['MySQL version'] = array(
2324
+ 'state' => 'ok',
2325
+ 'value' => @mysql_get_server_info( $wpdb->dbh ),
2326
+ );
2327
+
2328
+ //CURL presence and version
2329
+ if ( function_exists('curl_version') ){
2330
+ $version = curl_version();
2331
+
2332
+ if ( version_compare( $version['version'], '7.16.0', '<=' ) ){
2333
+ $data = array(
2334
+ 'state' => 'warning',
2335
+ 'value' => $version['version'],
2336
+ 'message' => 'You have an old version of CURL. Redirect detection may not work properly.',
2337
+ );
2338
+ } else {
2339
+ $data = array(
2340
+ 'state' => 'ok',
2341
+ 'value' => $version['version'],
2342
+ );
2343
+ }
2344
+
2345
+ } else {
2346
+ $data = array(
2347
+ 'state' => 'warning',
2348
+ 'value' => 'Not installed',
2349
+ );
2350
+ }
2351
+ $debug['CURL version'] = $data;
2352
+
2353
+ //Snoopy presence
2354
+ if ( class_exists('Snoopy') ){
2355
+ $data = array(
2356
+ 'state' => 'ok',
2357
+ 'value' => 'Installed',
2358
+ );
2359
+ } else {
2360
+ //No Snoopy? This should never happen, but if it does we *must* have CURL.
2361
+ if ( function_exists('curl_init') ){
2362
+ $data = array(
2363
+ 'state' => 'ok',
2364
+ 'value' => 'Not installed',
2365
+ );
2366
+ } else {
2367
+ $data = array(
2368
+ 'state' => 'error',
2369
+ 'value' => 'Not installed',
2370
+ 'message' => 'You must have either CURL or Snoopy installed for the plugin to work!',
2371
+ );
2372
+ }
2373
+
2374
+ }
2375
+ $debug['Snoopy'] = $data;
2376
+
2377
+ //Safe_mode status
2378
+ if ( ini_get('safe_mode') ){
2379
+ $debug['Safe mode'] = array(
2380
+ 'state' => 'warning',
2381
+ 'value' => 'On',
2382
+ 'message' => 'Redirects may be detected as broken links when safe_mode is on.',
2383
+ );
2384
+ } else {
2385
+ $debug['Safe mode'] = array(
2386
+ 'state' => 'ok',
2387
+ 'value' => 'Off',
2388
+ );
2389
+ }
2390
+
2391
+ //Open_basedir status
2392
+ if ( ini_get('open_basedir') ){
2393
+ $debug['open_basedir'] = array(
2394
+ 'state' => 'warning',
2395
+ 'value' => 'On',
2396
+ 'message' => 'Redirects may be detected as broken links when open_basedir is on.',
2397
+ );
2398
+ } else {
2399
+ $debug['open_basedir'] = array(
2400
+ 'state' => 'ok',
2401
+ 'value' => 'Off',
2402
+ );
2403
+ }
2404
+
2405
+ //Lockfile location
2406
+ $lockfile = $this->lockfile_name();
2407
+ if ( $lockfile ){
2408
+ $debug['Lockfile'] = array(
2409
+ 'state' => 'ok',
2410
+ 'value' => $lockfile,
2411
+ );
2412
+ } else {
2413
+ $debug['Lockfile'] = array(
2414
+ 'state' => 'error',
2415
+ 'message' => 'Can\'t create a lockfile. Please specify a custom temporary directory.',
2416
+ );
2417
+ }
2418
+
2419
+ return $debug;
2420
+ }
2421
 
2422
  }//class ends here
2423
 
highlighter-class.php CHANGED
@@ -7,6 +7,8 @@
7
  * @requires blcUtility
8
  */
9
 
 
 
10
  class blcLinkHighlighter {
11
 
12
  var $links_to_remove;
@@ -52,7 +54,16 @@ class blcLinkHighlighter {
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
  }
@@ -60,6 +71,7 @@ class blcLinkHighlighter {
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];
@@ -73,4 +85,5 @@ class blcLinkHighlighter {
73
  }
74
  }
75
 
 
76
  ?>
7
  * @requires blcUtility
8
  */
9
 
10
+ if ( !class_exists('blcLinkHighlighter') ){
11
+
12
  class blcLinkHighlighter {
13
 
14
  var $links_to_remove;
54
  $this->links_to_remove[$row['url']] = $row;
55
  }
56
  $content = preg_replace_callback( blcUtility::link_pattern(), array(&$this,'mark_broken_links'), $content );
57
+
58
+ if ( BLC_DEBUG ){
59
+ $content .= '<p><strong>Broken links in this post : </strong></p><ul>';
60
+ $content .= '<li>' . implode('</li><li>', array_keys($this->links_to_remove)) . '</li></ul>';
61
+ }
62
+ } else {
63
+ if ( BLC_DEBUG ){
64
+ $content .= '<p><strong>This post contains no broken links.</strong></p>';
65
+ }
66
+ };
67
 
68
  return $content;
69
  }
71
  function mark_broken_links($matches){
72
  //TODO: Tooltip-style popups with more info
73
  $url = blcUtility::normalize_url( html_entity_decode( $matches[3] ), $this->current_permalink );
74
+
75
  if( isset( $this->links_to_remove[$url] ) ){
76
  return $matches[1].$matches[2].$matches[3].$matches[2].' class="broken_link" '.$matches[4].
77
  $matches[5].$matches[6];
85
  }
86
  }
87
 
88
+ }
89
  ?>
link-classes.php CHANGED
@@ -94,7 +94,7 @@ class blcLink {
94
  *
95
  * @return bool
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
@@ -157,14 +157,16 @@ class blcLink {
157
  //Add a semi-plausible referer header to avoid tripping up some bot traps
158
  curl_setopt($ch, CURLOPT_REFERER, get_option('home'));
159
 
160
- curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
161
-
162
- @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 
163
  curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
164
-
165
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
166
- curl_setopt($ch, CURLOPT_TIMEOUT, 30);
167
 
 
 
 
 
168
  if (defined('WP_PROXY_HOST')) {
169
  curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
170
  }
@@ -181,25 +183,25 @@ class blcLink {
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);
191
  } else {
192
- $nobody=true;
193
- curl_setopt($ch, CURLOPT_NOBODY, true);
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
202
- $response = curl_exec($ch);
203
 
204
  $info = curl_getinfo($ch);
205
  $code = intval( $info['http_code'] );
@@ -211,10 +213,12 @@ class blcLink {
211
  $this->log .= "Trying a second time with different settings...\n";
212
  $this->last_headers = '';
213
 
214
- curl_setopt($ch, CURLOPT_NOBODY, false);
215
- curl_setopt($ch, CURLOPT_HTTPGET, true);
216
- curl_setopt($ch, CURLOPT_RANGE, '0-2047');
217
- $response = curl_exec($ch);
 
 
218
 
219
  $info = curl_getinfo($ch);
220
  $code = intval( $info['http_code'] );
@@ -238,7 +242,7 @@ class blcLink {
238
  $start_time = microtime_float(true);
239
 
240
  $snoopy = new Snoopy;
241
- $snoopy->read_timeout = 60; //read timeout in seconds
242
  $snoopy->maxlength = 1024*5; //load up to 5 kilobytes
243
  $snoopy->fetch($url);
244
 
94
  *
95
  * @return bool
96
  */
97
+ function check( $timeout = 40 ){
98
  if ( !$this->valid() ) return false;
99
 
100
  //General note : there is usually no need to save() the result of the check
157
  //Add a semi-plausible referer header to avoid tripping up some bot traps
158
  curl_setopt($ch, CURLOPT_REFERER, get_option('home'));
159
 
160
+ //Redirects don't work when safe mode or open_basedir is enabled.
161
+ if ( !ini_get('safe_mode') && !ini_get('open_basedir') ) {
162
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
163
+ }
164
  curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
 
 
 
165
 
166
+ //Set the timeout
167
+ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
168
+
169
+ //Set the proxy configuration. The user can provide this in wp-config.php
170
  if (defined('WP_PROXY_HOST')) {
171
  curl_setopt($ch, CURLOPT_PROXY, WP_PROXY_HOST);
172
  }
183
  curl_setopt($ch, CURLOPT_PROXYUSERPWD, $auth);
184
  }
185
 
186
+ //Is this even necessary?
187
  curl_setopt($ch, CURLOPT_FAILONERROR, false);
188
 
189
+ $nobody = false;
190
  if( $parts['scheme'] == 'https' ){
191
  //TODO: Redirects don't work with HTTPS
192
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
193
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
194
  } else {
195
+ $nobody = true;
196
+ curl_setopt($ch, CURLOPT_NOBODY, true); //Use the HEAD method for non-https URLs
 
197
  }
198
 
199
+ //Register a callback function which will process the HTTP header(s).
200
+ //It can be called multiple times if the remote server performs a redirect.
201
  curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this,'read_header'));
202
 
203
  //Execute the request
204
+ curl_exec($ch);
205
 
206
  $info = curl_getinfo($ch);
207
  $code = intval( $info['http_code'] );
213
  $this->log .= "Trying a second time with different settings...\n";
214
  $this->last_headers = '';
215
 
216
+ curl_setopt($ch, CURLOPT_NOBODY, false); //Don't send a HEAD request this time
217
+ curl_setopt($ch, CURLOPT_HTTPGET, true); //Switch back to GET instead.
218
+ curl_setopt($ch, CURLOPT_RANGE, '0-2047');//But limit the desired response size,
219
+ //we don't want to eat the user's bandwidth.
220
+ //Run it again
221
+ curl_exec($ch);
222
 
223
  $info = curl_getinfo($ch);
224
  $code = intval( $info['http_code'] );
242
  $start_time = microtime_float(true);
243
 
244
  $snoopy = new Snoopy;
245
+ $snoopy->read_timeout = $timeout; //read timeout in seconds
246
  $snoopy->maxlength = 1024*5; //load up to 5 kilobytes
247
  $snoopy->fetch($url);
248
 
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.13
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
 
@@ -60,7 +60,11 @@ To upgrade your installation
60
 
61
  *This is an automatically generated changelog*
62
 
63
- == Changelog ==
 
 
 
 
64
 
65
  = 0.5.13 =
66
  * Fixed the bug where the plugin would ignore FORCE\_ADMIN\_SSL setting and always use plain HTTP for it's forms and AJAX.
@@ -250,4 +254,5 @@ To upgrade your installation
250
  * *There are no release notes for this version*
251
 
252
  = 0.1 =
253
- * *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.14
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
 
60
 
61
  *This is an automatically generated changelog*
62
 
63
+ = 0.5.14 =
64
+ * Made the timeout value used when checking links user-configurable.
65
+ * The plugin will now report an error instead of failing silently when it can't create the necessary database tables.
66
+ * Added a table listing assorted debug info to the settings page. Click the small "Show debug info" link to display it.
67
+ * Cleaned up some redundant/useless code.
68
 
69
  = 0.5.13 =
70
  * Fixed the bug where the plugin would ignore FORCE\_ADMIN\_SSL setting and always use plain HTTP for it's forms and AJAX.
254
  * *There are no release notes for this version*
255
 
256
  = 0.1 =
257
+ * *There are no release notes for this version*
258
+
utility-class.php CHANGED
@@ -166,7 +166,8 @@ class blcUtility {
166
  $url
167
  );
168
  }
169
-
 
170
  }//class
171
 
172
  }//class_exists
166
  $url
167
  );
168
  }
169
+
170
+
171
  }//class
172
 
173
  }//class_exists