]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/LinkFilter.php
MediaWiki 1.16.0
[autoinstallsdev/mediawiki.git] / includes / LinkFilter.php
1 <?php
2
3 /**
4  * Some functions to help implement an external link filter for spam control.
5  * 
6  * @todo implement the filter. Currently these are just some functions to help
7  * maintenance/cleanupSpam.php remove links to a single specified domain. The
8  * next thing is to implement functions for checking a given page against a big
9  * list of domains.
10  *
11  * Another cool thing to do would be a web interface for fast spam removal.
12  */
13 class LinkFilter {
14
15         /**
16          * Check whether $text contains a link to $filterEntry
17          *
18          * @param $text String: text to check
19          * @param $filterEntry String: domainparts, see makeRegex() for more details
20          * @return Integer: 0 if no match or 1 if there's at least one match
21          */
22         static function matchEntry( $text, $filterEntry ) {
23                 $regex = LinkFilter::makeRegex( $filterEntry );
24                 return preg_match( $regex, $text );
25         }
26
27         /**
28          * Builds a regex pattern for $filterEntry.
29          *
30          * @param $filterEntry String: URL, if it begins with "*.", it'll be
31          *        replaced to match any subdomain
32          * @return String: regex pattern, for preg_match()
33          */
34         private static function makeRegex( $filterEntry ) {
35                 $regex = '!http://';
36                 if ( substr( $filterEntry, 0, 2 ) == '*.' ) {
37                         $regex .= '(?:[A-Za-z0-9.-]+\.|)';
38                         $filterEntry = substr( $filterEntry, 2 );
39                 }
40                 $regex .= preg_quote( $filterEntry, '!' ) . '!Si';
41                 return $regex;
42         }
43
44         /**
45          * Make a string to go after an SQL LIKE, which will match the specified
46          * string. There are several kinds of filter entry:
47          *     *.domain.com    -  Produces http://com.domain.%, matches domain.com
48          *                        and www.domain.com
49          *     domain.com      -  Produces http://com.domain./%, matches domain.com
50          *                        or domain.com/ but not www.domain.com
51          *     *.domain.com/x  -  Produces http://com.domain.%/x%, matches
52          *                        www.domain.com/xy
53          *     domain.com/x    -  Produces http://com.domain./x%, matches
54          *                        domain.com/xy but not www.domain.com/xy
55          *
56          * Asterisks in any other location are considered invalid.
57          * 
58          * @param $filterEntry String: domainparts
59          * @param $prot        String: protocol
60          * @return String
61          * @deprecated Use makeLikeArray() and pass result to Database::buildLike() instead
62          */
63          public static function makeLike( $filterEntry , $prot = 'http://' ) {
64                 wfDeprecated( __METHOD__ );
65
66                 $like = self::makeLikeArray( $filterEntry , $prot );
67                 if ( !$like ) {
68                         return false;
69                 }
70                 $dbw = wfGetDB( DB_MASTER );
71                 $s = $dbw->buildLike( $like );
72                 $m = false;
73                 if ( preg_match( "/^ *LIKE '(.*)' *$/", $s, $m ) ) {
74                         return $m[1];
75                 } else {
76                         throw new MWException( __METHOD__.': this DBMS is not supported by this function.' );
77                 }
78         }
79
80         /**
81          * Make an array to be used for calls to DatabaseBase::buildLike(), which
82          * will match the specified string. There are several kinds of filter entry:
83          *     *.domain.com    -  Produces http://com.domain.%, matches domain.com
84          *                        and www.domain.com
85          *     domain.com      -  Produces http://com.domain./%, matches domain.com
86          *                        or domain.com/ but not www.domain.com
87          *     *.domain.com/x  -  Produces http://com.domain.%/x%, matches
88          *                        www.domain.com/xy
89          *     domain.com/x    -  Produces http://com.domain./x%, matches
90          *                        domain.com/xy but not www.domain.com/xy
91          *
92          * Asterisks in any other location are considered invalid.
93          *
94          * @param $filterEntry String: domainparts
95          * @param $prot        String: protocol
96          * @return Array to be passed to DatabaseBase::buildLike() or false on error
97          */
98          public static function makeLikeArray( $filterEntry , $prot = 'http://' ) {
99                 $db = wfGetDB( DB_MASTER );
100                 if ( substr( $filterEntry, 0, 2 ) == '*.' ) {
101                         $subdomains = true;
102                         $filterEntry = substr( $filterEntry, 2 );
103                         if ( $filterEntry == '' ) {
104                                 // We don't want to make a clause that will match everything,
105                                 // that could be dangerous
106                                 return false;
107                         }
108                 } else {
109                         $subdomains = false;
110                 }
111                 // No stray asterisks, that could cause confusion
112                 // It's not simple or efficient to handle it properly so we don't
113                 // handle it at all.
114                 if ( strpos( $filterEntry, '*' ) !== false ) {
115                         return false;
116                 }
117                 $slash = strpos( $filterEntry, '/' );
118                 if ( $slash !== false ) {
119                         $path = substr( $filterEntry, $slash );
120                         $host = substr( $filterEntry, 0, $slash );
121                 } else {
122                         $path = '/';
123                         $host = $filterEntry;
124                 }
125                 // Reverse the labels in the hostname, convert to lower case
126                 // For emails reverse domainpart only
127                 if ( $prot == 'mailto:' && strpos($host, '@') ) {
128                         // complete email adress 
129                         $mailparts = explode( '@', $host );
130                         $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
131                         $host = $domainpart . '@' . $mailparts[0];
132                         $like = array( "$prot$host", $db->anyString() );
133                 } elseif ( $prot == 'mailto:' ) {
134                         // domainpart of email adress only. do not add '.'
135                         $host = strtolower( implode( '.', array_reverse( explode( '.', $host ) ) ) );   
136                         $like = array( "$prot$host", $db->anyString() );                        
137                 } else {
138                         $host = strtolower( implode( '.', array_reverse( explode( '.', $host ) ) ) );   
139                         if ( substr( $host, -1, 1 ) !== '.' ) {
140                                 $host .= '.';
141                         }
142                         $like = array( "$prot$host" );
143
144                         if ( $subdomains ) {
145                                 $like[] = $db->anyString();
146                         }
147                         if ( !$subdomains || $path !== '/' ) {
148                                 $like[] = $path;
149                                 $like[] = $db->anyString();
150                         }
151                 }
152                 return $like;
153         }
154
155         /**
156          * Filters an array returned by makeLikeArray(), removing everything past first pattern placeholder.
157          *
158          * @param $arr array: array to filter
159          * @return filtered array
160          */
161         public static function keepOneWildcard( $arr ) {
162                 if( !is_array( $arr ) ) {
163                         return $arr;
164                 }
165
166                 foreach( $arr as $key => $value ) {
167                         if ( $value instanceof LikeMatch ) {
168                                 return array_slice( $arr, 0, $key + 1 );
169                         }
170                 }
171
172                 return $arr;
173         }
174 }