1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
4 // | PHP Version 4 |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2003 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Author: Stijn de Reede <sjr@gmx.co.uk> |
17 // +----------------------------------------------------------------------+
18 //
19 // $Id: Links.php,v 1.12 2007/07/02 18:26:17 cweiske Exp $
20 //
21
22 /**
23 * @package sapphire
24 * @subpackage misc
25 * @author Stijn de Reede <sjr@gmx.co.uk>
26 */
27
28 /**
29 */
30 require_once 'HTML/BBCodeParser/Filter.php';
31
32 /**
33 * @package sapphire
34 * @subpackage misc
35 */
36 class SSHTMLBBCodeParser_Filter_Links extends SSHTMLBBCodeParser_Filter
37 {
38 /**
39 * List of allowed schemes
40 *
41 * @access private
42 * @var array
43 */
44 var $_allowedSchemes = array('http', 'https', 'ftp');
45
46 /**
47 * Default scheme
48 *
49 * @access private
50 * @var string
51 */
52 var $_defaultScheme = 'http';
53
54 /**
55 * An array of tags parsed by the engine
56 *
57 * @access private
58 * @var array
59 */
60 var $_definedTags = array(
61 'url' => array(
62 'htmlopen' => 'a',
63 'htmlclose' => 'a',
64 'allowed' => 'none^img',
65 'attributes'=> array('url' => 'href=%2$s%1$s%2$s')
66 )
67 );
68
69
70 /**
71 * Executes statements before the actual array building starts
72 *
73 * This method should be overwritten in a filter if you want to do
74 * something before the parsing process starts. This can be useful to
75 * allow certain short alternative tags which then can be converted into
76 * proper tags with preg_replace() calls.
77 * The main class walks through all the filters and and calls this
78 * method if it exists. The filters should modify their private $_text
79 * variable.
80 *
81 * @return none
82 * @access private
83 * @see $_text
84 * @author Stijn de Reede <sjr@gmx.co.uk>
85 * @author Seth Price <seth@pricepages.org>
86 */
87 function _preparse()
88 {
89 $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser', '_options');
90 $o = $options['open'];
91 $c = $options['close'];
92 $oe = $options['open_esc'];
93 $ce = $options['close_esc'];
94
95 $schemes = implode('|', $this->_allowedSchemes);
96
97 $pattern = array( "/(?<![\"'=".$ce."\/])(".$oe."[^".$ce."]*".$ce.")?(((".$schemes."):\/\/|www)[@-a-z0-9.]+\.[a-z]{2,4}[^\s()\[\]]*)/i",
98 "!".$oe."url(".$ce."|\s.*".$ce.")(.*)".$oe."/url".$ce."!iU",
99 "!".$oe."url=((([a-z]*:(//)?)|www)[@-a-z0-9.]+)([^\s\[\]]*)".$ce."(.*)".$oe."/url".$ce."!i");
100
101 $pp = preg_replace_callback($pattern[0], array($this, 'smarterPPLinkExpand'), $this->_text);
102 $pp = preg_replace($pattern[1], $o."url=\$2\$1\$2".$o."/url".$c, $pp);
103 $this->_preparsed = preg_replace_callback($pattern[2], array($this, 'smarterPPLink'), $pp);
104
105 }
106
107 /**
108 * Intelligently expand a URL into a link
109 *
110 * @return string
111 * @access private
112 * @author Seth Price <seth@pricepages.org>
113 * @author Lorenzo Alberton <l.alberton@quipo.it>
114 */
115 function smarterPPLinkExpand($matches)
116 {
117 $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser','_options');
118 $o = $options['open'];
119 $c = $options['close'];
120
121 //If we have an intro tag that is [url], then skip this match
122 if ($matches[1] == $o.'url'.$c) {
123 return $matches[0];
124 }
125
126 if(!BBCodeParser::autolinkUrls()){
127 return $matches[0];
128 }
129
130
131 $punctuation = '.,;:'; // Links can't end with these chars
132 $trailing = '';
133 // Knock off ending punctuation
134 $last = substr($matches[2], -1);
135 while (strpos($punctuation, $last) !== false) {
136 // Last character is punctuation - remove it from the url
137 $trailing = $last.$trailing;
138 $matches[2] = substr($matches[2], 0, -1);
139 $last = substr($matches[2], -1);
140 }
141
142 $off = strpos($matches[2], ':');
143
144 //Is a ":" (therefore a scheme) defined?
145 if ($off === false) {
146 /*
147 * Create a link with the default scheme of http. Notice that the
148 * text that is viewable to the user is unchanged, but the link
149 * itself contains the "http://".
150 */
151 return $matches[1].$o.'url='.$this->_defaultScheme.'://'.$matches[2].$c.$matches[2].$o.'/url'.$c.$trailing;
152 }
153
154 $scheme = substr($matches[2], 0, $off);
155
156 /*
157 * If protocol is in the approved list than allow it. Note that this
158 * check isn't really needed, but the created link will just be deleted
159 * later in smarterPPLink() if we create it now and it isn't on the
160 * scheme list.
161 */
162 if (in_array($scheme, $this->_allowedSchemes)) {
163 return $matches[1].$o.'url'.$c.$matches[2].$o.'/url'.$c.$trailing;
164 }
165
166 return $matches[0];
167 }
168
169 /**
170 * Finish preparsing URL to clean it up
171 *
172 * @return string
173 * @access private
174 * @author Seth Price <seth@pricepages.org>
175 */
176 function smarterPPLink($matches)
177 {
178 $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser','_options');
179 $o = $options['open'];
180 $c = $options['close'];
181
182 $urlServ = $matches[1];
183 $path = $matches[5];
184
185 $off = strpos($urlServ, ':');
186
187 if ($off === false) {
188 //Default to http
189 $urlServ = $this->_defaultScheme.'://'.$urlServ;
190 $off = strpos($urlServ, ':');
191 }
192
193 //Add trailing slash if missing (to create a valid URL)
194 if (!$path) {
195 $path = '/';
196 }
197
198 $protocol = substr($urlServ, 0, $off);
199
200 if (in_array($protocol, $this->_allowedSchemes)) {
201 //If protocol is in the approved list than allow it
202 return $o.'url='.$urlServ.$path.$c.$matches[6].$o.'/url'.$c;
203 }
204
205 //Else remove url tag
206 return $matches[6];
207 }
208 }
209 ?>