<?php
/*
Plugin Name: Spambot Email Protector
Description: Automatically encodes email addresses in your viewer pages to protect them from spambots and and email harvesters
Version: 2.02
Requires at least: 2.00A
*/

// Encoding Options - to disable an encoding method set to false;
$GLOBALS['SEP_ENCODING_METHODS']['decEntity']   = true;
$GLOBALS['SEP_ENCODING_METHODS']['hexEntity']   = true;
$GLOBALS['SEP_ENCODING_METHODS']['urlEncoding'] = true;
$GLOBALS['SEP_ENCODING_METHODS']['jsUnicode']   = true;
$GLOBALS['SEP_ENCODING_METHODS']['bdo']         = false;
$GLOBALS['SEP_ENCODING_METHODS']['comments']    = false;
$GLOBALS['SEP_ENCODING_METHODS']['tags']        = false;
$GLOBALS['SEP_ENCODING_METHODS']['jsLocation']  = false;

// DON'T UPDATE ANYTHING BELOW THIS LINE

if ( !defined('IS_CMS_ADMIN') && !@$GLOBALS['SEP_DISABLED'] ) {
  ob_start('SEP_replaceEmails', 2);
}

//
function SEP_replaceEmails($content) {

#  static $EMAIL_ONLY   = '((?:[\w\-]+[\w\-.])*[\w\-]+@(?:[\w\-]+[\w\-.])*[\w\-]+\.[A-Za-z]{2,8})';
  static $EMAIL_ONLY    = '([\w\-\.]+@[\w\-\.]+\.[A-Za-z]{2,8})'; # Note: This simplified email regexp requires less backtracking and prevents PREG_BACKTRACK_LIMIT_ERROR errors - see php docs for preg_last_error()

  // Replace mailto: emails in tags
  $mailtoRegexp         = '(<[^>]*?[\'"])mailto:' . $EMAIL_ONLY. '([\'"][^>]*>)';
  $mailtoReplacement    = create_function('$matches', 'return $matches[1] . _SEP_encodeEmail($matches[2], "MAILTO") . $matches[3];');
  $content              = preg_replace_callback("/$mailtoRegexp/i", $mailtoReplacement, $content);

  // Replace other emails in tags
  $tagEmailRegexp       = '(<[^>]*?)' . $EMAIL_ONLY;
  $tagEmailReplacement = create_function('$matches', 'return $matches[1] . _SEP_encodeEmail($matches[2], "INTAG");');
  $content              = preg_replace_callback("/$tagEmailRegexp/i", $tagEmailReplacement, $content);

  // Replace emails in text
  $textEmailRegexp      = '((?:^|>)[^<]*?)' . $EMAIL_ONLY;
  $textEmailReplacement = create_function('$matches', 'return $matches[1] . _SEP_encodeEmail($matches[2], "TEXT");');
  $content              = preg_replace_callback("/$textEmailRegexp/", $textEmailReplacement, $content);


  //
  return $content;
}


//
function _SEP_encodeEmail($email, $type) {
  if ($type != 'MAILTO' && $type != 'TEXT' && $type != 'INTAG') { die(__FUNCTION__ . "'type' must be either 'MAILTO', 'TEXT', or 'INTAG'"); }
  $inText   = ($type == 'TEXT');
  $inMailto = ($type == 'MAILTO');
  $inTag    = ($type == 'INTAG');
  $encodedEmail = $email;
  $mailto       = ($inMailto) ? "mailto:" : "";

  // NOTE:  All these filters work on the email as an array of characters or elements
  $chars = preg_split("//", $email, -1, PREG_SPLIT_NO_EMPTY);

  ### character encoding
  $encodingMethods = array();
  if ($GLOBALS['SEP_ENCODING_METHODS']['decEntity'])                { $encodingMethods[] = 'decEntity'; }
  if ($GLOBALS['SEP_ENCODING_METHODS']['hexEntity'])                { $encodingMethods[] = 'hexEntity'; }
  if ($GLOBALS['SEP_ENCODING_METHODS']['urlEncoding'] && $inMailto) { $encodingMethods[] = 'urlEncoding'; }
  if ($GLOBALS['SEP_ENCODING_METHODS']['jsUnicode'] &&
      $GLOBALS['SEP_ENCODING_METHODS']['jsLocation'] && $inMailto)  { $encodingMethods[] = 'jsUnicode'; }

  if (count($encodingMethods) > 0) {
    for ($index=0; $index < count($chars); $index++) {
      $methodIndex = mt_rand(0, count($encodingMethods)-1);
      $methodName  = $encodingMethods[$methodIndex];
      $char        = &$chars[$index];

      if      ($methodName == 'decEntity')   { $char = '&#' .ord($char). ';'; }
      else if ($methodName == 'hexEntity')   { $char = '&#x' .dechex(ord($char)). ';'; }
      else if ($methodName == 'urlEncoding') { $char = '%' .dechex(ord($char)); }
      else if ($methodName == 'jsUnicode')   { $char = '\u00' .dechex(ord($char)); }

      unset($char);
    }
  }

  // add html comments
  if (@$GLOBALS['SEP_ENCODING_METHODS']['comments'] && $inText) {
    foreach (range(1, mt_rand(2,5)) as $n) {
      $randomOffset = mt_rand(0, count($chars));
      $randomText   = chr(mt_rand(97,122)) . chr(mt_rand(97,122)) . chr(mt_rand(97,122));
      array_splice($chars, $randomOffset, 0, "<!-- $randomText -->");
    }
  }

  // add span tags
  if (@$GLOBALS['SEP_ENCODING_METHODS']['tags'] && $inText) {
    $randomOffset1  = mt_rand(0, count($chars));
    $randomOffset2  = mt_rand(0, count($chars));
    $lowerOffset    = min($randomOffset1, $randomOffset2);
    $higherOffset   = max($randomOffset1, $randomOffset2);

    // insert tags in reverse order if we're going to reverse content next
    $reversing      = @$GLOBALS['SEP_ENCODING_METHODS']['bdo'] && $inText;
    if ($reversing) {
      list($lowerOffset, $higherOffset) = array($higherOffset, $lowerOffset);
    }

    array_splice($chars, $lowerOffset, 0, "<span>");
    array_splice($chars, $higherOffset, 0, "</span>");
  }

  // <bdo> encoding
  if (@$GLOBALS['SEP_ENCODING_METHODS']['bdo'] && $inText) {
    $chars = array_reverse($chars);
    array_unshift($chars, '<bdo dir="rtl">');
    array_push($chars, '</bdo>');
  }


  // js-location encoding
  if (@$GLOBALS['SEP_ENCODING_METHODS']['jsLocation'] && $inMailto) {
    $mailto = 'javascript:void(window.location=%27mailto:';
    array_push($chars, '%27);');
  }

  // testplan mode (overrides all other modes)
  if (@$GLOBALS['SEP_ENCODING_METHODS']['testplan']) {
    $testplanEmail = preg_replace("/@/", "($type)", $email);
    $chars         = preg_split("//", $testplanEmail, -1, PREG_SPLIT_NO_EMPTY);
    $mailto        = ($inMailto) ? "mailto:" : "";
  }

  // combine chars back into email
  $encodedEmail = join('', $chars);

  //
  return $mailto . $encodedEmail;
}
