1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SMW\Parser; |
4
|
|
|
|
5
|
|
|
use SMW\InTextAnnotationParser; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* @license GNU GPL v2+ |
9
|
|
|
* @since 2.5 |
10
|
|
|
* |
11
|
|
|
* @author mwjames |
12
|
|
|
*/ |
13
|
|
|
class Obfuscator { |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @since 2.5 |
17
|
|
|
* |
18
|
|
|
* @param string $text |
19
|
|
|
* @param InTextAnnotationParser $parser |
20
|
|
|
* |
21
|
|
|
* @return text |
22
|
|
|
*/ |
23
|
|
|
public static function obfuscateLinks( $text, InTextAnnotationParser $parser ) { |
24
|
|
|
|
25
|
|
|
// Filter simple [ ... ] from [[ ... ]] links |
|
|
|
|
26
|
|
|
// Ensure to find the correct start and end in case of |
27
|
|
|
// [[Foo::[[Bar]]]] or [[Foo::[http://example.org/foo]]] |
|
|
|
|
28
|
|
|
$text = str_replace( |
29
|
|
|
array( '[', ']', '[[', ']]]]', ']]]', ']]' ), |
30
|
|
|
array( '[', ']', '[[', ']]]]', ']]]', ']]' ), |
31
|
|
|
$text |
32
|
|
|
); |
33
|
|
|
|
34
|
|
|
return self::doObfuscate( $text, $parser ); |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @since 2.5 |
39
|
|
|
* |
40
|
|
|
* @param string $text |
41
|
|
|
* |
42
|
|
|
* @return text |
43
|
|
|
*/ |
44
|
|
|
public static function removeLinkObfuscation( $text ) { |
45
|
|
|
return str_replace( |
46
|
|
|
array( '[', ']', '|' ), |
47
|
|
|
array( '[', ']', '|' ), |
48
|
|
|
$text |
49
|
|
|
); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @since 2.5 |
54
|
|
|
* |
55
|
|
|
* @param string $text |
56
|
|
|
* |
57
|
|
|
* @return text |
58
|
|
|
*/ |
59
|
|
|
public static function encodeLinks( $text ) { |
60
|
|
|
return str_replace( |
61
|
|
|
array( '[', ']', '|' ), |
62
|
|
|
array( '[', ']', '|' ), |
63
|
|
|
$text |
64
|
|
|
); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @since 2.5 |
69
|
|
|
* |
70
|
|
|
* @param string $text |
71
|
|
|
* |
72
|
|
|
* @return text |
73
|
|
|
*/ |
74
|
|
|
public static function decodeSquareBracket( $text ) { |
75
|
|
|
return str_replace( array( '%5B', '%5D' ), array( '[', ']' ), $text ); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @since 2.5 |
80
|
|
|
* |
81
|
|
|
* @param string $text |
82
|
|
|
* |
83
|
|
|
* @return text |
84
|
|
|
*/ |
85
|
|
|
public static function obfuscateAnnotation( $text ) { |
86
|
|
|
return preg_replace_callback( |
87
|
|
|
InTextAnnotationParser::getRegexpPattern( false ), |
88
|
|
|
function( array $matches ) { |
89
|
|
|
return str_replace( '[', '[', $matches[0] ); |
90
|
|
|
}, |
91
|
|
|
self::decodeSquareBracket( $text ) |
92
|
|
|
); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @since 2.5 |
97
|
|
|
* |
98
|
|
|
* @param string $text |
99
|
|
|
* |
100
|
|
|
* @return text |
101
|
|
|
*/ |
102
|
|
|
public static function removeAnnotation( $text ) { |
103
|
|
|
return preg_replace_callback( |
104
|
|
|
InTextAnnotationParser::getRegexpPattern( false ), |
105
|
|
|
'self::doRemoveAnnotation', |
106
|
|
|
self::decodeSquareBracket( $text ) |
107
|
|
|
); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
private static function doRemoveAnnotation( array $matches ) { |
|
|
|
|
111
|
|
|
|
112
|
|
|
$caption = false; |
113
|
|
|
$value = ''; |
114
|
|
|
|
115
|
|
|
// #1453 |
116
|
|
|
if ( $matches[0] === InTextAnnotationParser::OFF || $matches[0] === InTextAnnotationParser::ON ) { |
117
|
|
|
return false; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
// Strict mode matching |
121
|
|
|
if ( array_key_exists( 1, $matches ) ) { |
122
|
|
|
if ( strpos( $matches[1], ':' ) !== false && isset( $matches[2] ) ) { |
123
|
|
|
list( $matches[1], $matches[2] ) = explode( '::', $matches[1] . '::' . $matches[2], 2 ); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
if ( array_key_exists( 2, $matches ) ) { |
128
|
|
|
|
129
|
|
|
// #1747 |
130
|
|
|
if ( strpos( $matches[1], '|' ) !== false ) { |
131
|
|
|
return $matches[0]; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
$parts = explode( '|', $matches[2] ); |
135
|
|
|
$value = array_key_exists( 0, $parts ) ? $parts[0] : ''; |
136
|
|
|
$caption = array_key_exists( 1, $parts ) ? $parts[1] : false; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
// #... |
140
|
|
|
if ( $value === '@@@' ) { |
141
|
|
|
$value = ''; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
return $caption !== false ? $caption : $value; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
private static function doObfuscate( $text, $parser ) { |
148
|
|
|
|
149
|
|
|
// Find all [[ ... ]] |
|
|
|
|
150
|
|
|
preg_match_all('/\[{2}(.*?)\]{2}/is', $text, $matches ); |
151
|
|
|
$off = false; |
152
|
|
|
|
153
|
|
|
foreach ( $matches[0] as $match ) { |
154
|
|
|
|
155
|
|
|
// Ignore transformed links ([[:Foo|Foo]]) |
|
|
|
|
156
|
|
|
if ( strpos( $match, '[[:' ) !== false ) { |
157
|
|
|
continue; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
// Remember whether the text contains OFF/ON marker (added by |
161
|
|
|
// recursive parser, template, embedded result printer) and restore |
162
|
|
|
// the marker after the text has been processed |
163
|
|
|
if ( $off === false ) { |
164
|
|
|
$off = $match === InTextAnnotationParser::OFF; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
$openNum = substr_count( $match, '[[' ); |
168
|
|
|
$closeNum = substr_count( $match, ']]' ); |
169
|
|
|
$markerNum = substr_count( $match, '::' ); |
170
|
|
|
|
171
|
|
|
if ( $markerNum == 0 ) { |
172
|
|
|
// Simple link [[ ... ]], no annotation therefore match and |
173
|
|
|
// obfuscate [[, |, ]] for a matching text elements |
|
|
|
|
174
|
|
|
$text = str_replace( $match, self::encodeLinks( $match ), $text ); |
175
|
|
|
} elseif ( $openNum > $closeNum && $markerNum == 1 ) { |
176
|
|
|
// [[Text::Some [[abc]] |
|
|
|
|
177
|
|
|
// Forget about about the first position |
178
|
|
|
$replace = str_replace( $match, self::encodeLinks( $match ), $match ); |
179
|
|
|
$replace = substr_replace( $replace, '[[', 0, 10 ); |
180
|
|
|
$text = str_replace( $match, $replace, $text ); |
181
|
|
|
} elseif ( $openNum === $closeNum && $markerNum == 1 ) { |
182
|
|
|
// [[Foo::Bar]] annotation therefore run a pattern match and |
183
|
|
|
// obfuscate the returning [[, |, ]] result |
|
|
|
|
184
|
|
|
$replace = self::encodeLinks( preg_replace_callback( |
185
|
|
|
$parser->getRegexpPattern( false ), |
186
|
|
|
array( $parser, 'preprocess' ), |
187
|
|
|
$match |
188
|
|
|
) ); |
189
|
|
|
$text = str_replace( $match, $replace, $text ); |
190
|
|
|
} elseif ( $openNum > $closeNum && $markerNum == 2 ) { |
191
|
|
|
// [[Text::Some [[Foo::Some]] |
|
|
|
|
192
|
|
|
// Remove the first [[ and added after results are returned |
193
|
|
|
$text = str_replace( $match, '[[' . self::doObfuscate( substr( $match, 2 ), $parser ), $text ); |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
// Restore OFF/ON |
198
|
|
|
if ( $off === true ) { |
199
|
|
|
$text = InTextAnnotationParser::OFF . $text . InTextAnnotationParser::ON; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
return $text; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
} |
206
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.