View previous topic :: View next topic |
Author |
Message |
andre Smarty Pro
Joined: 23 Apr 2003 Posts: 164 Location: Karlsruhe, Germany
|
Posted: Tue Mar 16, 2004 8:30 am Post subject: [Output Filter] Obfuscating email addresses |
|
|
Hi,
for a very small CMS I wrote I needed an output filter which obfuscates all email addresses to prevent spam robots from harvesting them. To use the Smarty built-in {mailto} plugin wasn't possible here.
So here's the plugin code which works very well for me :
[php:1:3890828dcf]
<?php
function smarty_outputfilter_obfuscate_email( $tpl_source, &$smarty ) {
preg_match_all('!<a\s([^>]*)href=["\']mailto:([^"\']+)["\']([^>]*)>(.*?)</a[^>]*>!is', $tpl_source, $matches);
// $matches[0] contains full matched string: <a href="...">...</a>
// $matches[1] contains additional parameters
// $matches[2] contains the email address which was specified as href
// $matches[3] contains additional parameters
// $matches[4] contains the text between the opening and closing <a> tag
$replace = $matches[0];
foreach ($matches[0] as $key => $match) {
$address = $matches[2][$key];
$obfuscated_address = str_replace(array(".","@"), array(" dot ", " at "), $address);
$extra = trim($matches[1][$key]." ".$matches[3][$key]);
$text = $matches[4][$key];
$obfuscated_text = str_replace(array(".","@"), array(" dot ", " at "), $text);
$string = "var e; if (e = document.getElementById('obfuscated_email_".$key."')) e.style.display = 'none';\n";
$string .= "document.write('<a href=\"mailto:".$address."\" ".$extra.">".$text."</a>');";
$js_encode = '';
for ($x=0; $x < strlen($string); $x++) {
$js_encode .= '%' . bin2hex($string[$x]);
}
$replace[$key] = '<a id="obfuscated_email_'.$key.'" href="mailto:'.$obfuscated_address.'">'.$obfuscated_text.'</a><script type="text/javascript" language="javascript">eval(unescape(\''.$js_encode.'\'))</script>';
}
$tpl_source = str_replace($matches[0], $replace, $tpl_source);
return $tpl_source;
}
?>
[/php:1:3890828dcf]
This filter plugin replaces all <a href=" ... "> ... </a> tags with a special JavaScript code which cannot be harvested. The code is based upon the original {mailto} plugin. I also included an additional text which is shown to users who disabled JavaScript. In this case the address is displayed this way: myname at example dot com
Feedback is welcome |
|
Back to top |
|
sopel Smarty n00b
Joined: 07 Jul 2004 Posts: 1
|
Posted: Tue Feb 01, 2005 8:55 pm Post subject: |
|
|
not everyone has javascript enabled. i would rather suggest much simpler modifier :
[php:1:2753b696a2]
function smarty_modifier_antispam($string)
{
$converted_str = '';
for ($i = 0,$count = strlen($string); $i<; $i++) {
$converted_str .= ''.ord(substr($string, $i, 1)).';';
}
return $converted_str;
}
[/php:1:2753b696a2]
probably it's not so (much) effective as javascript method, but works everywhere. _________________ http://sopel.webd.pl |
|
Back to top |
|
ingenious Smarty Rookie
Joined: 17 Mar 2005 Posts: 15 Location: Sofia, Bulgaria
|
Posted: Thu Mar 17, 2005 5:39 pm Post subject: |
|
|
The above given function is already in the list of functions that come along with Smarty:
Code: | <a href="mailto:{$EmailAddress|escape:"hex"}">{$EmailAddress|escape:"hexentity"}</a> |
|
|
Back to top |
|
mohrt Administrator
Joined: 16 Apr 2003 Posts: 7368 Location: Lincoln Nebraska, USA
|
Posted: Thu Mar 17, 2005 5:49 pm Post subject: |
|
|
There is also a {mailto} function that comes with Smarty that does much of the same. It is not an output filter though, it must be specified in the template.
http://smarty.php.net/mailto |
|
Back to top |
|
php_pete Smarty n00b
Joined: 25 Sep 2005 Posts: 2
|
Posted: Sun Sep 25, 2005 8:21 pm Post subject: |
|
|
This is a great piece of code and saved me a load of hassle when I wanted to obfuscate email addressed in database stored html, which meant that I couldn't use the email smarty tags.
I found a problem with the code though. If you have the same email address repeated on a single page then the str_replace function replaces all those email addresses with the first regex match. This means that all the ids of the obfuscated email addresses are the same (obfuscated_email_0) and wreaks havoc when the javascript tries to do its stuff.
Here is an alternative which uses a rather nasty global variable. Any body got any better ideas?
[php:1:c08f228f24]
<?php
function smarty_outputfilter_obfuscate_email( $tpl_source, &$smarty ) {
global $obfuscated_email_count;
$obfuscated_email_count = 0;
$tpl_source = preg_replace_callback(
'!<a\s([^>]*)href=["\']mailto:([^"\']+)["\']([^>]*)>(.*?)</a[^>]*>!is',
'do_it',
$tpl_source);
return $tpl_source;
}
function do_it($matches) {
global $obfuscated_email_count;
// $matches[0] contains full matched string: <a href="...">...</a>
// $matches[1] contains additional parameters
// $matches[2] contains the email address which was specified as href
// $matches[3] contains additional parameters
// $matches[4] contains the text between the opening and closing <a> tag
$address = $matches[2];
$obfuscated_address = str_replace(array(".","@"), array(" dot ", " at "), $address);
$extra = trim($matches[1]." ".$matches[3]);
$text = $matches[4];
$obfuscated_text = str_replace(array(".","@"), array(" dot ", " at "), $text);
$string = "var e; if (e = document.getElementById('obfuscated_email_".$obfuscated_email_count."')) e.style.display = 'none';\n";
$string .= "document.write('<a href=\"mailto:".$address."\" ".$extra.">".$text."</a>');";
$js_encode = '';
for ($x=0; $x < strlen($string); $x++) {
$js_encode .= '%' . bin2hex($string[$x]);
}
$replace = '<a id="obfuscated_email_'.$obfuscated_email_count.'" href="mailto:'.$obfuscated_address.'">'.$obfuscated_text.'</a><script type="text/javascript" language="javascript">eval(unescape(\''.$js_encode.'\'))</script>';
++$obfuscated_email_count;
return $replace;
}
?>
[/php:1:c08f228f24]
Pete |
|
Back to top |
|
boots Administrator
Joined: 16 Apr 2003 Posts: 5611 Location: Toronto, Canada
|
Posted: Sun Sep 25, 2005 11:27 pm Post subject: |
|
|
Maybe make $obfuscated_email_count a member var on the $smarty object and then put do_it as a method on the object. In your callback you would use array($smarty, 'do_it') as the callback param. Just an idea. |
|
Back to top |
|
php_pete Smarty n00b
Joined: 25 Sep 2005 Posts: 2
|
Posted: Mon Sep 26, 2005 7:28 am Post subject: |
|
|
That does the trick nicely thanks.
I was playing with the idea of enclosing the entire plugin in a class but still had to have a global object of that class kicking around.
It would have been good if we could have had plug classes as well as callbacks so then we could have more power over these kinds of things. And then we wouldn't need to stick these things into the smarty class and maintain a bit more encapsulation of the functionality. |
|
Back to top |
|
alarconcepts Smarty Rookie
Joined: 28 May 2005 Posts: 18 Location: NY
|
Posted: Sun Aug 06, 2006 9:55 am Post subject: |
|
|
I needed an output filter that converts both html email-links and text-emails into ASCII equivalents. When all else fails, roll your own, right? So I did...
ASCII Email Encoder
Enjoy!
- John |
|
Back to top |
|
|