Community Documentation

obfuscate (hide) all emails from spammers

Last updated August 26, 2009. Created by adixon on May 10, 2006.
Edited by ronald_istos, Senpai, add1sun, Dublin Drupaller. Log in to edit this page.

Here's a way to obfuscate emails from spam harvesters using just your theme.

Setting aside the question of whether it really works and how long it might work, on this particular site we wanted the site-wide but weak protection that this provides. Most of the existing obfuscation techniques are parts of modules, but here the more reliable (and potentially efficient?) mechanism is to do all your obfuscation at once at the theme level. In this case, the emails were being exposed by the civicrm module in the profiles.

The actual obfuscation is done by encoding the address in javascript so that most users won't actually notice, with the usual obfuscation as a fallback if the user has no javascript.

So here it is in two parts:

1. In your template.php file, add these two functions:

function _phptemplate_encode_mailto($mail) {
  $link = 'document.write(\'<a href="mailto:' . $mail . '">' . $mail . '</a>\');';
  $js_encode = '';  for ($x = 0; $x < strlen($link); $x++) {
    $js_encode .= '%' . bin2hex($link{$x});
  }

  $link = '<script type="text/javascript" language="javascript">eval(unescape(\''.$js_encode.'\'))</script>';
  $link .= '<noscript>'.str_replace(array('@','.'),array(' at ',' dot '),$mail). '</noscript>';
  return $link;
}

function phptemplate_safemail($text) {
  if (strpos($text, '@') === FALSE)
    return $text;
  // Split at <a> and </a> so that we can avoid encoding addresses in link text.
  $t = preg_replace(":(</?a):i", "\001\\1", strtr($text, "\r\n", "\002\003"));
  $a = explode("\001", $t);
  $n = count($a);

  for ($i = 0; $i < $n; ++$i) {
    if (preg_match('/^(<a[^>]*)mailto:([^@]+@[-.a-z0-9]+)(.*)/i', $a[$i], $m)) {
      $a[$i] = _phptemplate_encode_mailto($m[2]);
      $a[1+$i] = substr($a[1+$i],4);
    }
  
    else if (!preg_match('/^(.*)(<input[^>]+)[-.a-z0-9]+@[-.a-z0-9]+.*\/>/i',$a[$i])) {
      while (preg_match('/(.*)[^-.a-z0-9]([-.a-z0-9]+)(@[-.a-z0-9]+)(.*)$/i', $a[$i], $m)) {
        $a[$i] = $m[1] . _phptemplate_encode_mailto($m[2].$m[3]) .  $m[4];
      }
    }
  }
  return strtr(implode('', $a), "\002\003", "\r\n");
}

...and then add this fragment inside php tags in your page.tpl.php page (before the $content gets printed of course..).

It won't obfuscate emails in the /admin section or on edit forms. There may be some other pages that you don't want obfuscated as well.

<?php
if (function_exists('phptemplate_safemail') && ('admin' != arg(0))) :
 
$larg = arg(-1 + count(explode('/', $_GET['q'])));
  if (
'edit' != $larg) {
   
$content = phptemplate_safemail($content);
  }
endif;
?>

With thanks to:

and apologies if this looks like a repeat of a forum article I posted, it is (someone suggested this is a better spot for it).

Comments

Just a note of caution

If the email address is immediately adjacent to an HTML tag (such as

info@site.com) the closing angle bracket gets thrown out or gobbled out. I haven't found a programmatic solution, but just inserting a space between the bracket and the email address sorts it.

Eish!

Fix for adjacent HTML tag

Just change the while loop to match this one. Seems to fix the problem here.

<?php
     
while (preg_match('/(.*)([^-.a-z0-9])([-.a-z0-9]+)(@[-.a-z0-9]+)(.*)$/i', $a[$i], $m)) {
       
$a[$i] = $m[1] . $m[2] . _phptemplate_encode_mailto($m[3].$m[4]) .  $m[5];
      }
?>

Test

Is there any way to know whether this code is working aside from not getting errors once making these additions to the template and page.tpl? Is there a way to test it out?

Thanks

About this page

Drupal version
Drupal 4.7.x, Drupal 5.x
Audience
Designers/themers, Programmers, Site administrators

Theming Guide

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.