WordPress.org

Plugin Directory

Changeset 356436


Ignore:
Timestamp:
03/07/11 03:13:09 (3 years ago)
Author:
joelhardi
Message:

Version bump to 0.9. Fix for database-integrated bbPress installs. Added list of user accounts pending deletion to the settings page. Various minor changes. See changelog in readme.txt for details.

Location:
user-spam-remover/trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • user-spam-remover/trunk/readme.txt

    r286933 r356436  
    44Tags: user, users, registration, spam, admin 
    55Requires at least: 3.0.0 
    6 Tested up to: 3.0.1 
     6Tested up to: 3.1 
    77Stable tag: trunk 
    88 
     
    8787== Changelog == 
    8888 
     89= 0.9 = 
     90 +  Version/compatibility bump so that wordpress.org plugin repository info is 
     91    accurate. 
     92 +  Added check for wp_usermeta 'last_posted' record so that users of 
     93    database-integrated bbPress installations are not deleted if they have ever 
     94    posted anything. 
     95 +  Added hard limit of 5000 records to prevent long-running operations. 
     96 +  Added a list of user accounts pending deletion to the settings page. 
     97 +  Style fix to inline error messages per r16205 changes to WordPress core  
     98    file wp-admin/css/colors-fresh.dev.css. 
     99 +  Miscellaneous minor style fixes. 
     100 
    89101= 0.3 = 
    90102 +  Added standard WordPress Users section icon and printing of status message 
  • user-spam-remover/trunk/user-spam-remover.php

    r286933 r356436  
    44Plugin URI: http://lyncd.com/user-spam-remover/ 
    55Description: Automatically removes spam user registrations and other old, never-used user accounts. Blocks annoying e-mail to administrator after every new registration. Full logging and backup of deleted data. Requires PHP5. After activating, go to <a href="users.php?page=user_spam_remover">settings page</a> to enable. 
    6 Version: 0.3 
     6Version: 0.9 
    77Author: Joel Hardi 
    88Author URI: http://lyncd.com/ 
     
    1010*/ 
    1111 
    12 /*  Copyright 2010 Joel Hardi 
     12/*  Copyright 2010-2011 Joel Hardi 
    1313 
    1414    This program is free software; you can redistribute it and/or modify 
     
    207207      $usp->checkEnabled(TRUE); 
    208208?> 
    209   <form method="post" action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI']); ?>" style="float: right; text-align: right; width: 20em; overflow: hidden;"><input type="hidden" name="<?php echo $removeNowBool; ?>" value="1" /> 
    210     <p class="submit" style="margin: 0.8em 0 0 0; padding: 0;"> 
     209  <form method="post" action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI']); ?>" style="float: right; text-align: right; width: 22em; overflow: hidden;"><input type="hidden" name="<?php echo $removeNowBool; ?>" value="1" /> 
     210    <p class="submit" style="margin: 0.8em 0 0; padding: 0;"> 
    211211      <input type="submit" class="button-primary" value="Remove spam/unused accounts now" /> 
    212212    </p><?php wp_nonce_field($nonceRemoveUsersNow); ?> 
     
    240240                         trim(implode('', $lines)), $matches)) { 
    241241            echo "<h4>Latest $linesToPrint lines in activity log</h4>\n"; 
    242             echo '<pre style="background: white; overflow: auto; max-height: 6em; padding: 0.5em;">'; 
     242            echo '<pre style="background: white; overflow: auto; max-height: 5em; padding: 0.5em;">'; 
    243243            echo $matches[0]."</pre>\n"; 
    244244          } 
     
    246246      } 
    247247    } 
     248 
     249    // Preview users pending deletion 
     250    $maxShow = 300; 
     251    $days = self::sanitizePosInt($usp->getOption('daysGrace')); 
     252    if ($usp->getOption('enabled')) { 
     253      if ($days > 0) 
     254        $days = $days - 1; 
     255      echo "<h4>Unused accounts pending deletion</h4>\n"; 
     256      echo "<p>These unused user accounts are within 24 hours of the age threshold you've set below and will be automatically deleted in the next 48 hours.</p>\n"; 
     257      $users = $usp->getIDList($days, TRUE); 
     258    } else { 
     259      echo "<h4>Unused accounts over the age threshold</h4>\n"; 
     260      echo "<p>These unused user accounts are older than the age threshold you've set below. To remove them, either enable automatic deletion or click the \"Remove spam/unused accounts now\" button above.</p>\n"; 
     261      $users = $usp->getIDList($days, TRUE); 
     262    } 
     263    echo '<p style="background: white; overflow: auto; max-height: 5em; padding: 0.5em;">'; 
     264    if (count($users) > 0) { 
     265      $shown = 0; 
     266      foreach ($users as $id => $login) { 
     267        // for $edit_link, see WP_Users_List_Table::single_row() in  
     268        // wp-admin/includes/class-wp-users-list-table.php 
     269        $edit_link = esc_url( 
     270          add_query_arg('wp_http_referer',  
     271                        urlencode(stripslashes($_SERVER['REQUEST_URI'])),  
     272                        "user-edit.php?user_id=$id")); 
     273        echo '<a href="'.$edit_link.'">'.$login.'</a> '; 
     274        $shown++; 
     275        if ($shown == $maxShow) { 
     276          $leftover = count($users) - $shown; 
     277          if ($leftover > 0) 
     278            echo " and $leftover more"; 
     279          break; 
     280        } 
     281      } 
     282    } else { 
     283      echo "no matching accounts found"; 
     284    } 
     285    echo "</p>\n"; 
    248286?> 
    249287  <h3>Settings</h3> 
     
    258296  }  
    259297?> 
    260     <p>Set <strong>User Spam Remover</strong> to automatically delete all unused user accounts (those users who have never commented, posted or added a link) older than the age threshold. The main target is user registration spam, but <strong>all</strong> orphaned, never-used accounts are included. Optionally, you can whitelist specific usernames to protect them from deletion (i.e., your boss' account that he has never used), but we recommend<strong>not</strong> using this feature because dormant, neglected accounts are often those used in backdoor attacks.</p> 
     298    <p>Set <strong>User Spam Remover</strong> to automatically delete all unused user accounts (those users who have never commented, posted or added a link) older than the age threshold. The main target is user registration spam, but <strong>all</strong> orphaned, never-used accounts are included. Optionally, you can whitelist specific usernames to protect them from deletion (i.e., your boss' account that he has never used), but we recommend <strong>not</strong> using this feature because dormant, neglected accounts are often those used in backdoor attacks.</p> 
    261299    <table class="form-table"> 
    262300      <tr valign="top"><?php $o = self::$wpOptGroup.'enabled'; ?> 
     
    370408  // Prints WordPress <div class="error"><p> style msg inline 
    371409  public static function errorMsg($str) { 
    372     echo '<p class="error" style="padding: 0.6em;"><strong>'. 
    373          $str."</strong></p>\n"; 
     410    echo '<div class="error inline"><p><strong>'.$str."</strong></p></div>\n"; 
    374411  } 
    375412 
    376413  public function remove() { 
    377     $pre = $this->wpdb->prefix; 
    378     $db = $this->wpdb->dbh; 
    379  
    380414    // Check pruning is enabled and log files are writable if they're enabled 
    381415    try { 
     
    389423    } 
    390424 
    391     // Format escaped SQL for username whitelist if it is non-empty 
    392     $wlSQL = ''; 
    393     if ($whitelist = $this->getOption('userWhitelist')) { 
    394       $ns = preg_split("#[\s,]+#", trim($whitelist)); 
    395       $us = array(); 
    396       foreach ($ns as $n) { 
    397         if (strlen($n) > 0) 
    398           $us[] = "'".mysql_real_escape_string($n)."'"; 
    399       } 
    400       if (count($us) > 0) 
    401         $wlSQL = 'AND u.user_login NOT IN ('.implode(', ', $us).')'; 
    402     } 
    403  
    404     // Remove unused user records older than daysGrace. Cancel remove and 
    405     // roll back database if there's a problem writing to restore log 
     425    $pre = $this->wpdb->prefix; 
     426    $db = $this->wpdb->dbh; 
    406427    $days = self::sanitizePosInt($this->getOption('daysGrace')); 
    407428    if ($days != 1) 
     
    409430    else 
    410431      $daysPlural = ''; 
    411     $sql = "SELECT u.ID FROM ${pre}users AS u ". 
    412            "LEFT OUTER JOIN ${pre}comments AS c ON u.ID = c.user_id ". 
    413            "LEFT OUTER JOIN ${pre}posts AS p ON u.ID = p.post_author ". 
    414            "LEFT OUTER JOIN ${pre}links AS l ON u.ID = l.link_owner ". 
    415            "WHERE (c.comment_approved = 'spam' OR c.user_id IS NULL) ". 
    416            "AND p.post_author IS NULL AND l.link_owner IS NULL $wlSQL ". 
    417            "AND u.user_registered < DATE_ADD(NOW(), INTERVAL -$days DAY) ". 
    418            "GROUP BY u.ID;"; 
    419     mysql_query("BEGIN", $db); 
    420     $result = mysql_query($sql, $db); 
    421     if ($result and mysql_num_rows($result) > 0) { 
    422       while ($row = mysql_fetch_row($result)) { 
    423         $ids[] = $row[0]; 
    424       } 
    425       mysql_free_result($result); 
     432 
     433    // Remove identified unused user records. Cancel remove and roll back  
     434    // database if there's a problem writing to restore log 
     435    $ids = $this->getIDList($days); 
     436    if (count($ids) > 0) { 
     437      // Format list of users to delete 
    426438      $idList = implode(', ', $ids); 
    427439      $idCnt = count($ids); 
     
    432444      $this->timestamp = time(); 
    433445      $error = FALSE; 
     446 
     447      // Begin SQL transation 
     448      mysql_query("BEGIN", $db); 
    434449 
    435450      // Back up users about to be deleted 
     
    488503  } 
    489504 
     505  // Logs $str to activity log if debugging and logging are enabled 
     506  // (and log file is writable) 
     507  public function logDebug($str) { 
     508    if (self::$debug) 
     509      return $this->logAction('debug: '.$str); 
     510    else 
     511      return FALSE; 
     512  } 
     513 
    490514  // Prepend date and save $str (should be a single line only) to activity log. 
    491515  // Returns TRUE on success or FALSE on failure (i.e. log file not writable) 
     
    504528  } 
    505529 
    506   // Logs $str to activity log if debugging and logging are enabled 
    507   // (and log file is writable) 
    508   public function logDebug($str) { 
    509     if (self::$debug) 
    510       return $this->logAction('debug: '.$str); 
    511     else 
    512       return FALSE; 
     530  // Returns array of user IDs to delete older than $daysGrace 
     531  //  * if $returnNames is TRUE, returns assoc array(id => user_login) 
     532  protected function getIDList($daysGrace, $returnNames = FALSE) { 
     533    $pre = $this->wpdb->prefix; 
     534    $db = $this->wpdb->dbh; 
     535 
     536    // Format escaped SQL for username whitelist if it is non-empty 
     537    $wlSQL = ''; 
     538    if ($whitelist = $this->getOption('userWhitelist')) { 
     539      $ns = preg_split("#[\s,]+#", trim($whitelist)); 
     540      $us = array(); 
     541      foreach ($ns as $n) { 
     542        if (strlen($n) > 0) 
     543          $us[] = "'".mysql_real_escape_string($n)."'"; 
     544      } 
     545      if (count($us) > 0) 
     546        $wlSQL = 'AND u.user_login NOT IN ('.implode(', ', $us).')'; 
     547    } 
     548 
     549    // Identify unused user records older than $daysGrace and populate $ids 
     550    $ids = array(); 
     551    $select = 'u.ID'; 
     552    if ($returnNames) 
     553      $select .= ', u.user_login'; 
     554    $sql = "SELECT $select FROM ${pre}users AS u ". 
     555           "LEFT OUTER JOIN ${pre}comments AS c ON u.ID = c.user_id ". 
     556           "LEFT OUTER JOIN ${pre}posts AS p ON u.ID = p.post_author ". 
     557           "LEFT OUTER JOIN ${pre}links AS l ON u.ID = l.link_owner ". 
     558           "WHERE (c.comment_approved = 'spam' OR c.user_id IS NULL) ". 
     559           "AND p.post_author IS NULL AND l.link_owner IS NULL $wlSQL ". 
     560           "AND u.user_registered < DATE_ADD(NOW(), INTERVAL -$daysGrace DAY) ". 
     561           "GROUP BY u.ID LIMIT 5000;"; 
     562    $result = mysql_query($sql, $db); 
     563    if ($result and mysql_num_rows($result) > 0) { 
     564      while ($row = mysql_fetch_row($result)) { 
     565        if ($returnNames) 
     566          $ids[$row[0]] = $row[1]; 
     567        else 
     568          $ids[] = $row[0]; 
     569      } 
     570      mysql_free_result($result); 
     571 
     572      // Protect users with a usermeta record where meta_key = 'last_posted'. 
     573      // Database-integrated bbPress installations set/update this value when a 
     574      // user posts, so we will protect database-integrated bbPress users 
     575      // from deletion if they have written a post. 
     576      $sql = str_replace('WHERE',  
     577        "LEFT OUTER JOIN ${pre}usermeta AS m ON u.ID = m.user_id WHERE", $sql); 
     578      $sql = str_replace('AND p.post',  
     579        "AND m.meta_key = 'last_posted' AND p.post", $sql); 
     580      $result = mysql_query($sql, $db); 
     581      if ($result and mysql_num_rows($result) > 0) { 
     582        while ($row = mysql_fetch_row($result)) { 
     583          $key = array_search($row[0], $ids, TRUE); 
     584          if ($key !== FALSE) 
     585            unset($ids[$key]); 
     586        } 
     587        mysql_free_result($result); 
     588      } 
     589    } 
     590 
     591    return $ids; 
    513592  } 
    514593 
Note: See TracChangeset for help on using the changeset viewer.