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