]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/specials/SpecialLinkSearch.php
MediaWiki 1.17.0
[autoinstallsdev/mediawiki.git] / includes / specials / SpecialLinkSearch.php
1 <?php
2 /**
3  * Implements Special:LinkSearch
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup SpecialPage
22  * @author Brion Vibber
23  */
24  
25
26 /**
27  * Special:LinkSearch to search the external-links table.
28  */
29 function wfSpecialLinkSearch( $par ) {
30
31         list( $limit, $offset ) = wfCheckLimits();
32         global $wgOut, $wgUrlProtocols, $wgMiserMode, $wgLang;
33         $target = $GLOBALS['wgRequest']->getVal( 'target', $par );
34         $namespace = $GLOBALS['wgRequest']->getIntorNull( 'namespace', null );
35
36         $protocols_list[] = '';
37         foreach( $wgUrlProtocols as $prot ) {
38                 $protocols_list[] = $prot;
39         }
40
41         $target2 = $target;
42         $protocol = '';
43         $pr_sl = strpos($target2, '//' );
44         $pr_cl = strpos($target2, ':' );
45         if ( $pr_sl ) {
46                 // For protocols with '//'
47                 $protocol = substr( $target2, 0 , $pr_sl+2 );
48                 $target2 = substr( $target2, $pr_sl+2 );
49         } elseif ( !$pr_sl && $pr_cl ) {
50                 // For protocols without '//' like 'mailto:'
51                 $protocol = substr( $target2, 0 , $pr_cl+1 );
52                 $target2 = substr( $target2, $pr_cl+1 );
53         } elseif ( $protocol == '' && $target2 != '' ) {
54                 // default
55                 $protocol = 'http://';
56         }
57         if ( !in_array( $protocol, $protocols_list ) ) {
58                 // unsupported protocol, show original search request
59                 $target2 = $target;
60                 $protocol = '';
61         }
62
63         $self = Title::makeTitle( NS_SPECIAL, 'Linksearch' );
64
65         $wgOut->allowClickjacking();
66         $wgOut->addWikiMsg( 'linksearch-text', '<nowiki>' . $wgLang->commaList( $wgUrlProtocols ) . '</nowiki>' );
67         $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
68                 Html::hidden( 'title', $self->getPrefixedDbKey() ) .
69                 '<fieldset>' .
70                 Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
71                 Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
72         if ( !$wgMiserMode ) {
73                 $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
74                         Xml::namespaceSelector( $namespace, '' );
75         }
76         $s .=   Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
77                 '</fieldset>' .
78                 Xml::closeElement( 'form' );
79         $wgOut->addHTML( $s );
80
81         if( $target != '' ) {
82                 $searcher = new LinkSearchPage;
83                 $searcher->setParams( array( 
84                         'query' => $target2, 
85                         'namespace' => $namespace, 
86                         'protocol' => $protocol ) );
87                 $searcher->doQuery( $offset, $limit );
88         }
89 }
90
91 /**
92  * @ingroup SpecialPage
93  */
94 class LinkSearchPage extends QueryPage {
95         function setParams( $params ) {
96                 $this->mQuery = $params['query'];
97                 $this->mNs = $params['namespace'];
98                 $this->mProt = $params['protocol'];
99         }
100
101         function getName() {
102                 return 'LinkSearch';
103         }
104
105         /**
106          * Disable RSS/Atom feeds
107          */
108         function isSyndicated() {
109                 return false;
110         }
111
112         /**
113          * Return an appropriately formatted LIKE query and the clause
114          */
115         static function mungeQuery( $query , $prot ) {
116                 $field = 'el_index';
117                 $rv = LinkFilter::makeLikeArray( $query , $prot );
118                 if ($rv === false) {
119                         // LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
120                         if (preg_match('/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/', $query)) {
121                                 $dbr = wfGetDB( DB_SLAVE );
122                                 $rv = array( $prot . rtrim($query, " \t*"), $dbr->anyString() );
123                                 $field = 'el_to';
124                         }
125                 }
126                 return array( $rv, $field );
127         }
128
129         function linkParameters() {
130                 global $wgMiserMode;
131                 $params = array();
132                 $params['target'] = $this->mProt . $this->mQuery;
133                 if( isset( $this->mNs ) && !$wgMiserMode ) {
134                         $params['namespace'] = $this->mNs;
135                 }
136                 return $params;
137         }
138
139         function getSQL() {
140                 global $wgMiserMode;
141                 $dbr = wfGetDB( DB_SLAVE );
142                 $page = $dbr->tableName( 'page' );
143                 $externallinks = $dbr->tableName( 'externallinks' );
144
145                 /* strip everything past first wildcard, so that index-based-only lookup would be done */
146                 list( $munged, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
147                 $stripped = LinkFilter::keepOneWildcard( $munged );
148                 $like = $dbr->buildLike( $stripped );
149
150                 $encSQL = '';
151                 if ( isset ($this->mNs) && !$wgMiserMode )
152                         $encSQL = 'AND page_namespace=' . $dbr->addQuotes( $this->mNs );
153
154                 $use_index = $dbr->useIndexClause( $clause );
155                 return
156                         "SELECT
157                                 page_namespace AS namespace,
158                                 page_title AS title,
159                                 el_index AS value,
160                                 el_to AS url
161                         FROM
162                                 $page,
163                                 $externallinks $use_index
164                         WHERE
165                                 page_id=el_from
166                                 AND $clause $like
167                                 $encSQL";
168         }
169
170         function formatResult( $skin, $result ) {
171                 $title = Title::makeTitle( $result->namespace, $result->title );
172                 $url = $result->url;
173                 $pageLink = $skin->linkKnown( $title );
174                 $urlLink = $skin->makeExternalLink( $url, $url );
175
176                 return wfMsgHtml( 'linksearch-line', $urlLink, $pageLink );
177         }
178
179         /**
180          * Override to check query validity.
181          */
182         function doQuery( $offset, $limit, $shownavigation=true ) {
183                 global $wgOut;
184                 list( $this->mMungedQuery,  ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt );
185                 if( $this->mMungedQuery === false ) {
186                         $wgOut->addWikiMsg( 'linksearch-error' );
187                 } else {
188                         // For debugging
189                         // Generates invalid xhtml with patterns that contain --
190                         //$wgOut->addHTML( "\n<!-- " . htmlspecialchars( $this->mMungedQuery ) . " -->\n" );
191                         parent::doQuery( $offset, $limit, $shownavigation );
192                 }
193         }
194
195         /**
196          * Override to squash the ORDER BY.
197          * We do a truncated index search, so the optimizer won't trust
198          * it as good enough for optimizing sort. The implicit ordering
199          * from the scan will usually do well enough for our needs.
200          */
201         function getOrder() {
202                 return '';
203         }
204 }