Project

General

Profile

1
<?php
2
/**
3
 * protect email addresses (replace '@' and '.' and obfuscate address
4
 * @param string $content
5
 * @return string
6
 */
7
    function doFilterEmail($content) {
8
        $aFilterSettings = getOutputFilterSettings();
9
        $key = preg_replace('=^.*?filter([^\.\/\\\\]+)(\.[^\.]+)?$=is', '\1', __FILE__);
10
        if ($aFilterSettings[$key]) {
11
            if (
12
                $aFilterSettings['OutputFilterMode'] == 0 &&
13
                $aFilterSettings['at_replacement'] == '@' &&
14
                $aFilterSettings['dot_replacement'] == '.'
15
            ) {
16
                return $content;
17
            }
18
        // test if js-decryption is installed
19
            if( preg_match('/<head.*<.*src=\".*\/mdcr.js.*>.*<\/head/siU', $content) ) {
20
                $aFilterSettings['OutputFilterMode'] |= pow(2, 2); // n | 2^2
21
            }else {
22
            // try to insert js-decrypt into <head> if available
23
                $script = str_replace('\\', '/',str_replace(WB_PATH,'', dirname(__DIR__)).'/js/mdcr.js');
24
                if(is_readable(WB_PATH.$script)) {
25
                    $scriptLink = "\t".'<script src="'.WB_URL.$script.'" type="text/javascript"></script>'."\n";
26
                    $regex = '/(.*)(<\s*?\/\s*?head\s*>.*)/isU';
27
                    $replace = '$1'.$scriptLink.'$2';
28
                    $content = preg_replace ($regex, $replace, $content);
29
                    $aFilterSettings['OutputFilterMode'] |= pow(2, 2); // n | 2^2
30
                }
31
            }
32
/* *** obfuscate mailto addresses by js:mdcr *** */
33
            // work out the defined output filter mode: possible output filter modes: [0], 1, 2, 3, 6, 7
34
            // 2^0 * (0.. disable, 1.. enable) filtering of mail addresses in text
35
            // 2^1 * (0.. disable, 1.. enable) filtering of mail addresses in mailto links
36
            // 2^2 * (0.. disable, 1.. enable) Javascript mailto encryption (only if mailto filtering enabled)
37

    
38
            // first search part to find all mailto email addresses
39
//            $pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>';
40
// bugfix 20160417
41
            $pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>\s*)(.*?)</a>';
42
            // second part to find all non mailto email addresses
43
            $pattern .= '|(value\s*=\s*"|\')??\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b#i';
44
/*
45
(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>|(value\s*=\s*"|\')??\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b
46
        Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)            -->    "<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
47
        Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})            -->    the email address in the mailto: part of the mail link
48
        Sub 3:([^"]*?)"                                                --> possible ?Subject&cc... stuff attached to the mail address
49
        Sub 4:([^>]*>)                                                --> all class or id statements after the mailto but before closing ..>
50
        Sub 5:(.*?)</a>\b                                            --> the mailto text; all characters between >xxxxx</a>
51
        Sub 6:|\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b        --> email addresses which may appear in the text (require word boundaries)
52
*/
53
            // find all email addresses embedded in the content and filter them using a callback function
54
            $content = preg_replace_callback(
55
                $pattern,
56
    /* ************************************************************************** */
57
                function ($match) use ($aFilterSettings) {
58
                    // check if required arguments are defined
59
                    $search = array('@', '.');
60
                    $replace = array($aFilterSettings['at_replacement'] ,$aFilterSettings['dot_replacement']);
61
                    // check if the match contains the expected number of subpatterns (6|8)
62
                    switch (count($match)) {
63
                        case 8:
64
                        /** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT **/
65
                        // 1.. text mails only, 3.. text mails + mailto (no JS), 7 text mails + mailto (JS)
66
                            if(!in_array($aFilterSettings['OutputFilterMode'], array(1,3,5,7))){ return $match[0]; }
67
                            // do not filter mail addresses included in input tags (<input ... value = "test@mail)
68
                            if (strpos($match[6], 'value') !== false) return $match[0]; {
69
                            // filtering of non mailto email addresses enabled
70
                                return str_replace($search, $replace, $match[0]);
71
                            }
72
                        break;
73
                        case 6:
74
                        /** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS **/
75
                        // 2.. mailto only (no JS), 3.. text mails + mailto (no JS), 6.. mailto only (JS), 7.. all filters active
76
                            if(!in_array($aFilterSettings['OutputFilterMode'], array(2,3,6,7))){ return $match[0]; }
77
                            // check if last part of the a href link: >xxxx</a> contains a email address we need to filter
78
                            $pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
79
                            if(preg_match_all($pattern, $match[5], $matches)) {
80
                                foreach($matches as $submatch) {
81
                                    foreach($submatch as $value) {
82
                                    // replace all . and all @ in email address parts by (dot) and (at) strings
83
                                        $match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
84
                                    }
85
                                }
86
                            }
87
                            // check if Javascript encryption routine is enabled
88
                            if(in_array($aFilterSettings['OutputFilterMode'], array(6,7))) {
89
                            /** USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
90
                            // extract possible class and id attribute from ahref link
91
                                preg_match('/class\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $class_attr);
92
                                $class_attr = empty($class_attr) ? '' : 'class="' . $class_attr[2] . '" ';
93
                                preg_match('/id\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $id_attr);
94
                                $id_attr = empty($id_attr) ? '' : 'id="' . $id_attr[2] . '" ';
95
                            // preprocess mailto link parts for further usage
96
                                $search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
97
                                $email_address = str_replace($search, $replace, strtolower($match[2]));
98
                                $email_subject = rawurlencode(html_entity_decode($match[3]));
99
                            // create a random encryption key for the Caesar cipher
100
                                mt_srand((double)microtime()*1000000);    // (PHP < 4.2.0)
101
                                $shift = mt_rand(1, 25);
102
                            // encrypt the email using an adapted Caesar cipher
103
                                $encrypted_email = "";
104
                                for($i = strlen($email_address) -1; $i > -1; $i--) {
105
                                    if(preg_match('#[FZXK0-9]#', $email_address[$i], $characters)) {
106
                                        $encrypted_email .= $email_address[$i];
107
                                    } else {
108
                                        $encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
109
                                    }
110
                                }
111
                                $encrypted_email .= chr($shift + 97);
112
                            // build the encrypted Javascript mailto link
113
                                $mailto_link  = "<a {$class_attr}{$id_attr}href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
114
                                return $mailto_link;
115
                            } else {
116
                            /** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
117
                            // as minimum protection, replace @ in the mailto part by (at)
118
                            // dots are not transformed as this would transform my.name@domain.com into: my(dot)name(at)domain(dot)com
119
                            // rebuild the mailto link from the subpatterns (at the missing characters " and </a>")
120
                                return $match[1].str_replace('@', $aFilterSettings['at_replacement'],$match[2]).$match[3].'"'.$match[4].$match[5].'</a>';
121
                            // if you want to protect both, @ and dots, comment out the line above and remove the comment from the line below
122
                            // return $match[1] .str_replace($search, $replace, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
123
                            }
124
                        break;
125
                        default:
126
                    // number of subpatterns do not match the requirements ... do nothing
127
                            return $match[0];
128
                        break;
129
                    }
130
                },
131
    /* ************************************************************************** */
132
                $content
133
            );
134
        }
135
        return $content;
136
    }
(3-3/12)