1: <?php
2: /**
3: * The Horde_Text_Filter_Emails:: class finds email addresses in a block of
4: * text and turns them into links.
5: *
6: * Parameters:
7: * <pre>
8: * class - (string) CSS class of the generated <a> tag.
9: * DEFAULT: ''
10: * encode - (boolean) Whether to escape special HTML characters in the URLs
11: * and finally "encode" the complete tag so that it can be decoded
12: * later with the decode() method. This is useful if you want to run
13: * htmlspecialchars() or similar *after* using this filter.
14: * DEFAULT: false
15: * </pre>
16: *
17: * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
18: *
19: * See the enclosed file COPYING for license information (LGPL). If you
20: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
21: *
22: * @author Tyler Colbert <tyler@colberts.us>
23: * @author Jan Schneider <jan@horde.org>
24: * @category Horde
25: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
26: * @package Text_Filter
27: */
28: class Horde_Text_Filter_Emails extends Horde_Text_Filter_Base
29: {
30: /**
31: * Filter parameters.
32: *
33: * @var array
34: */
35: protected $_params = array(
36: 'class' => '',
37: 'encode' => false
38: );
39:
40: /**
41: * Returns a hash with replace patterns.
42: *
43: * @return array Patterns hash.
44: */
45: public function getPatterns()
46: {
47: $this->_regexp = <<<EOR
48: /
49: # Version 1: mailto: links with any valid email characters.
50: # Pattern 1: Outlook parenthesizes in square brackets
51: (\[\s*)?
52: # Pattern 2: mailto: protocol prefix
53: (mailto:\s?)
54: # Pattern 3: email address
55: ([^\s\?"<&]*)
56: # Pattern 4: closing angle brackets?
57: (>)?
58: # Pattern 5 to 7: Optional parameters
59: ((\?)([^\s"<]*[\w+#?\/&=]))?
60: # Pattern 8: Closing Outlook square bracket
61: ((?(1)\s*\]))
62: |
63: # Version 2 Pattern 9 and 10: simple email addresses.
64: (^|\s|<|<|\[)([\w-+.=]+@[-A-Z0-9.]*[A-Z0-9])
65: # Pattern 11 to 13: Optional parameters
66: ((\?)([^\s"<]*[\w+#?\/&=]))?
67: # Pattern 14: Optional closing bracket
68: (>)?
69: /ix
70: EOR;
71:
72: return array('regexp_callback' => array(
73: $this->_regexp => array($this, 'regexCallback')
74: ));
75: }
76:
77: /**
78: * Regular expression callback.
79: *
80: * @param array $matches preg_replace_callback() matches. See regex above
81: * for description of matching data.
82: *
83: * @return string Replacement string.
84: */
85: public function regexCallback($matches)
86: {
87: $data = $this->_regexCallback($matches);
88:
89: if ($this->_params['encode']) {
90: $data = "\01\01\01" . base64_encode($data) . "\01\01\01";
91: }
92:
93: return $matches[1] . $matches[2] . (isset($matches[9]) ? $matches[9] : '') .
94: $data .
95: $matches[4] . $matches[8] . (isset($matches[14]) ? $matches[14] : '');
96: }
97:
98: /**
99: * Regular expression callback.
100: *
101: * @param array $matches preg_replace_callback() matches. See regex above
102: * for description of matching data.
103: *
104: * @return string Replacement string.
105: */
106: protected function _regexCallback($matches)
107: {
108: $class = empty($this->_params['class'])
109: ? ''
110: : ' class="' . $this->_params['class'] . '"';
111: $email = (!isset($matches[10]) || $matches[10] === '')
112: ? $matches[3] . $matches[5]
113: : $matches[10] . (isset($matches[11]) ? $matches[11] : '');
114:
115: return '<a' . $class . ' href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($email) . '</a>';
116: }
117:
118: /**
119: * "Decodes" the text formerly encoded by using the "encode" parameter.
120: *
121: * @param string $text An encoded text.
122: *
123: * @return string The decoded text.
124: */
125: static public function decode($text)
126: {
127: return preg_replace('/\01\01\01([\w=+\/]*)\01\01\01/e', 'base64_decode(\'$1\')', $text);
128: }
129:
130: }
131: