Subversion Repositories php_antispam

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. // ========================================================================
  4.  
  5. // SOURCE: SIGMA 3.0 ANTISPAM CONFIG
  6.  
  7. define('CFG_MAKE_MAIL_ADDRESSES_CLICKABLE', true);
  8. define('CFG_CORRET_MISSING_MAILTO', true);
  9. define('CFG_DEFAULT_CLASS', 'mail-addr');
  10.  
  11. // ========================================================================
  12.  
  13. // SOURCE: SIGMA 3.0 ANTISPAM FILTER
  14.  
  15. function secure_email_triv($email)
  16. {
  17.         if (!function_exists('alas_js_crypt'))
  18.         {
  19.                 function alas_js_crypt($text)
  20.                 {
  21.                         $tmp = '';
  22.                         for ($i=0; $i<strlen($text); $i++)
  23.                         {
  24.                                 $tmp .= 'document.write("&#'.ord(substr($text, $i, 1)).';");';
  25.                         }
  26.                         return $tmp;
  27.                 }
  28.         }
  29.  
  30.         $aus = '';
  31.         if ($email != '')
  32.         {
  33.                 $aus .= '<script language="JavaScript" type="text/javascript"><!--'."\n";
  34.                 $aus .= alas_js_crypt($email);
  35.                 $aus .= '// --></script>';
  36.         }
  37.         return $aus;
  38. }
  39.  
  40. function getAddrSpec() {
  41.         // Ref: http://www.iamcal.com/publish/articles/php/parsing_email/
  42.  
  43.         $qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
  44.         $dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
  45.         $atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
  46.         $quoted_pair = '\\x5c[\\x00-\\x7f]';
  47.         $domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
  48.         $quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
  49.         $domain_ref = $atom;
  50.         $sub_domain = "($domain_ref|$domain_literal)";
  51.         $word = "($atom|$quoted_string)";
  52.         $domain = "$sub_domain(\\x2e$sub_domain)*";
  53.         $local_part = "$word(\\x2e$word)*";
  54.         $addr_spec = "$local_part\\x40$domain";
  55.  
  56.         return $addr_spec;
  57. }
  58.  
  59. function is_valid_email_address($email) {
  60.         // TODO: Hier lieber einen korrekten Mailvalidator verwenden (C.Sayers Lösung)?
  61.  
  62.         $ary = explode('?', $email);
  63.         $email = $ary[0];
  64.  
  65.         $addr_spec = getAddrSpec();
  66.         return preg_match("!^$addr_spec$!", $email);
  67. }
  68.  
  69. class MailLinkProtector extends UrlParseIterator {
  70.         var $correct_missing_mailto;
  71.  
  72.         protected function link_callback($complete, $pre, $post, $urltype, $bracket, $url, $linktext) {
  73.                 if (beginsWithI($url, 'mailto:')) {
  74.                         // Link ist eine Mailadresse
  75.                         $mailaddr = remove_beginning_i($url, 'mailto:');
  76.                         return secure_email($mailaddr, $linktext, is_valid_email_address($linktext), CFG_DEFAULT_CLASS);
  77.                 } else if (($this->correct_missing_mailto) && (is_valid_email_address($url))) {
  78.                         // Hier hat jemand "mailto:" vergessen. Wir korrigieren das mal...
  79.                         $mailaddr = $url;
  80.                         return secure_email($mailaddr, $linktext, is_valid_email_address($linktext), CFG_DEFAULT_CLASS);
  81.                 } else {
  82.                         // Normaler Link
  83.                         return $complete;
  84.                 }
  85.         }
  86. }
  87.  
  88. function link_cb_2($a) {
  89.         $mailaddr = $a[1]; // Letztes
  90.  
  91.         if (CFG_MAKE_MAIL_ADDRESSES_CLICKABLE) {
  92.                 return secure_email($mailaddr, $mailaddr, true, CFG_DEFAULT_CLASS);
  93.         } else {
  94.                 return secure_email_triv($mailaddr);
  95.         }
  96. }
  97.  
  98. function protect_mail_address_urls($content, $correct_missing_mailto = true) {
  99.         $t = new MailLinkProtector;
  100.         $t->correct_missing_mailto = $correct_missing_mailto;
  101.         return $t->process($content);
  102. }
  103.  
  104. function auto_secure_mail_addresses($content) {
  105.         // Step 1: Parse links and make them secure
  106.  
  107.         $content = protect_mail_address_urls($content, CFG_CORRET_MISSING_MAILTO);
  108.  
  109.         // Step 2: Find all further mail addresses, make then clickable and prevent spam bots
  110.  
  111.         $addr_spec = getAddrSpec();
  112.  
  113.         // This fixes an error if the file is unix converted...
  114.         // The error occoured at server4.configcenter.info:
  115.         // [Fri Mar 26 20:23:24 2010] [error] [client 87.165.172.145] (104)Connection reset by peer: FastCGI: comm with server "/home/www/web66/html/cgi-bin/php-fcgi-starter" aborted: read failed
  116.         // [Fri Mar 26 20:23:24 2010] [error] [client 87.165.172.145] FastCGI: incomplete headers (0 bytes) received from server "/home/www/web66/html/cgi-bin/php-fcgi-starter"
  117.         $content = str_replace("\n", "\r\n", $content);
  118.  
  119.         // Diese Zeichen ausschließen, damit z.B. Satzzeichen am Ende einer E-Mail-Adresse, Anführungszeichen oder Klammern nicht
  120.         // als Teil der Adresse angesehen werden. Die Liste ist länger als $addr_spec eigentlich benötigt (z.B. schließt $addr_spec
  121.         // einen Punkt am Ende automatisch aus). Aber sicher ist sicher.
  122.         $exclude_mail_chars_beginning = '\^°!"§$%&/()=\?´`}\]\[{\+*~\'#-_\.:,;';
  123.         $exclude_mail_chars_ending = $exclude_mail_chars_beginning;
  124.  
  125.         $content = preg_replace_callback("@(?![$exclude_mail_chars_beginning])($addr_spec)(?<![$exclude_mail_chars_ending])@sm", 'link_cb_2', $content);
  126.  
  127.         // Output
  128.  
  129.         return $content;
  130. }
  131.  
  132. // ========================================================================
  133.  
  134. // SOURCE: SIGMA 3.0 _sigma.php
  135.  
  136. class UrlParseIterator {
  137.         var $use_original_bracket_at_link = false;
  138.         var $use_original_bracket_at_css = false;
  139.         var $use_original_bracket_at_other = false;
  140.  
  141.         protected function process_url($url) {
  142.                 // Overwrite this method in a derivate!
  143.                 return $url;
  144.         }
  145.  
  146.         // LINK
  147.  
  148.         private function link_style_regex() {
  149.                 return "@(<a\s[^>]*(href)\s*=\s*)(?(?=[\"'])(([\"'])([^>]*)\\4)|()([^ >]*?))([^>]*>)(.*)</a>@ismU";
  150.         }
  151.  
  152.         protected function link_callback($complete, $pre, $post, $urltype, $bracket, $url, $linktext) {
  153.                 $url = $this->process_url($url);
  154.  
  155.                 return $pre.$bracket.$url.$bracket.$post.$linktext.'</a>';
  156.         }
  157.  
  158.         private function link_first_callback($c) {
  159.                 $complete = $c[0];
  160.  
  161.                 $pre = $c[1];
  162.                 $post = $c[8];
  163.  
  164.                 $urltype = $c[2]; // = href
  165.  
  166.                 if ($this->use_original_bracket_at_link) {
  167.                         $bracket = $c[4];
  168.                 } else {
  169.                         $bracket = '"';
  170.                 }
  171.  
  172.                 $url = $c[5].$c[7]; // Either [5] OR [7] is filled, so I simply concat them.
  173.  
  174.                 $linktext = $c[9];
  175.  
  176.                 return $this->link_callback($complete, $pre, $post, $urltype, $bracket, $url, $linktext);
  177.         }
  178.  
  179.         // CSS
  180.  
  181.         private function css_style_regex() {
  182.                 return "/url\(\s*(?(?=[\"'])(([\"'])([^>]*)\\2)|([^\)]*?))\)/isUm";
  183.         }
  184.  
  185.         protected function css_callback($complete, $bracket, $url) {
  186.                 $url = $this->process_url($url);
  187.  
  188.                 return 'url('.$bracket.$url.$bracket.')';
  189.         }
  190.  
  191.         private function css_first_callback($c) {
  192.                 $complete = $c[0];
  193.  
  194.                 if ($this->use_original_bracket_at_css) {
  195.                         $bracket = $c[2];
  196.                 } else {
  197.                         $bracket = "'";
  198.                 }
  199.  
  200.                 if (!isset($c[4])) $c[4] = '';
  201.                 $url = $c[3].$c[4]; // Either [3] OR [4] is filled, so I simply concat them.
  202.  
  203.                 return $this->css_callback($complete, $bracket, $url);
  204.         }
  205.  
  206.         // Other (does not include a-href, but base-href etc.)
  207.  
  208.         private function other_style_regex() {
  209.                 return "/((<(?!a\s)[^><]*)(href)|src|background|code)\s*=\s*(?(?=[\"'])(([\"'])([^>]*)\\5)|([^ >]*?))/isUm";
  210.         }
  211.  
  212.         protected function other_callback($complete, $bracket, $type, $url) {
  213.                 $url = $this->process_url($url);
  214.  
  215.                 return $type.'='.$bracket.$url.$bracket;
  216.         }
  217.  
  218.         private function other_first_callback($c) {
  219.                 // Aufgrund des regex ist bei einem href $c[0] nicht href="..." sondern <base ... href="..."
  220.                 // Wir verdecken diesen zusätzlichen Anfang, leiten ihn an die abstrakte callback-Funktion weiter
  221.                 // und fügen später beim zurückliefern diesen Präfix $pre wieder hinzu.
  222.                 $pre = $c[2];
  223.  
  224.                 $complete = remove_beginning($c[0], $pre);
  225.  
  226.                 if ($c[3] == '') {
  227.                         $type = $c[1];
  228.                 } else {
  229.                         $type = $c[3];
  230.                 }
  231.  
  232.                 if ($this->use_original_bracket_at_other) {
  233.                         $bracket = $c[5];
  234.                 } else {
  235.                         $bracket = '"';
  236.                 }
  237.  
  238.                 if (!isset($c[7])) $c[7] = '';
  239.                 $url = $c[6].$c[7]; // Either [6] OR [7] is filled, so I simply concat them.
  240.  
  241.                 return $pre.$this->other_callback($complete, $bracket, $type, $url);
  242.         }
  243.  
  244.         // Processing functions
  245.  
  246.         private function process_links($content) {
  247.                 $r = preg_replace_callback($this->link_style_regex(), array(&$this, 'link_first_callback'), $content);
  248.                 if ($r == null) return $content; // z.B. bei doppeltem ALAS-Processing!
  249.                 return $r;
  250.         }
  251.  
  252.         private function process_other($content) {
  253.                 $r = preg_replace_callback($this->other_style_regex(), array(&$this, 'other_first_callback'), $content);
  254.                 if ($r == null) return $content;
  255.                 return $r;
  256.         }
  257.  
  258.         private function process_css($content) {
  259.                 $r = preg_replace_callback($this->css_style_regex(), array(&$this, 'css_first_callback'), $content);
  260.                 if ($r == null) return $content;
  261.                 return $r;
  262.         }
  263.  
  264.         public function process($content) {
  265.                 $content = $this->process_links($content);
  266.                 $content = $this->process_other($content);
  267.                 $content = $this->process_css($content);
  268.  
  269.                 return $content;
  270.         }
  271. }
  272.  
  273. // ========================================================================
  274.  
  275. // SOURCE: VIATHINKSOFT ANTI SPAM
  276.  
  277. include '../v3.inc.php';
  278.  
  279. // ========================================================================
  280.  
  281. // SOURCE: SIGMA 3.0 _sigma.php
  282.  
  283. function remove_beginning($content, $beginning) {
  284.         if (beginsWith($content, $beginning)) {
  285.                 return substr($content, strlen($beginning), strlen($content)-strlen($beginning));
  286.         } else {
  287.                 return $content;
  288.         }
  289. }
  290.  
  291. function beginsWithI($content, $beginning) {
  292.         return beginsWith(strtolower($content), strtolower($beginning));
  293. }
  294.  
  295. function beginsWith($content, $beginning) {
  296.         // return substr($content, 0, strlen($beginning)) == $beginning;
  297.         return (strncmp($content, $beginning, strlen($beginning)) == 0);
  298. }
  299.  
  300. function remove_beginning_i($content, $beginning) {
  301.         if (beginsWithI($content, $beginning)) {
  302.                 return substr($content, strlen($beginning), strlen($content)-strlen($beginning));
  303.         } else {
  304.                 return $content;
  305.         }
  306. }
  307.  
  308. // ========================================================================
  309.  
  310. // USAGE:
  311. // $content = auto_secure_mail_addresses($content);
  312.  
  313. // ========================================================================
  314.