Subversion Repositories php_antispam

Rev

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