MediaWiki  REL1_22
SpecialLinkSearch.php
Go to the documentation of this file.
00001 <?php
00029 class LinkSearchPage extends QueryPage {
00030     function setParams( $params ) {
00031         $this->mQuery = $params['query'];
00032         $this->mNs = $params['namespace'];
00033         $this->mProt = $params['protocol'];
00034     }
00035 
00036     function __construct( $name = 'LinkSearch' ) {
00037         parent::__construct( $name );
00038     }
00039 
00040     function isCacheable() {
00041         return false;
00042     }
00043 
00044     function execute( $par ) {
00045         global $wgUrlProtocols, $wgMiserMode, $wgScript;
00046 
00047         $this->setHeaders();
00048         $this->outputHeader();
00049 
00050         $out = $this->getOutput();
00051         $out->allowClickjacking();
00052 
00053         $request = $this->getRequest();
00054         $target = $request->getVal( 'target', $par );
00055         $namespace = $request->getIntorNull( 'namespace', null );
00056 
00057         $protocols_list = array();
00058         foreach ( $wgUrlProtocols as $prot ) {
00059             if ( $prot !== '//' ) {
00060                 $protocols_list[] = $prot;
00061             }
00062         }
00063 
00064         $target2 = $target;
00065         $protocol = '';
00066         $pr_sl = strpos( $target2, '//' );
00067         $pr_cl = strpos( $target2, ':' );
00068         if ( $pr_sl ) {
00069             // For protocols with '//'
00070             $protocol = substr( $target2, 0, $pr_sl + 2 );
00071             $target2 = substr( $target2, $pr_sl + 2 );
00072         } elseif ( !$pr_sl && $pr_cl ) {
00073             // For protocols without '//' like 'mailto:'
00074             $protocol = substr( $target2, 0, $pr_cl + 1 );
00075             $target2 = substr( $target2, $pr_cl + 1 );
00076         } elseif ( $protocol == '' && $target2 != '' ) {
00077             // default
00078             $protocol = 'http://';
00079         }
00080         if ( $protocol != '' && !in_array( $protocol, $protocols_list ) ) {
00081             // unsupported protocol, show original search request
00082             $target2 = $target;
00083             $protocol = '';
00084         }
00085 
00086         $out->addWikiMsg(
00087             'linksearch-text',
00088             '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
00089             count( $protocols_list )
00090         );
00091         $s = Html::openElement(
00092             'form',
00093             array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $wgScript )
00094         ) . "\n" .
00095             Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n" .
00096             Html::openElement( 'fieldset' ) . "\n" .
00097             Html::element( 'legend', array(), $this->msg( 'linksearch' )->text() ) . "\n" .
00098             Xml::inputLabel(
00099                 $this->msg( 'linksearch-pat' )->text(),
00100                 'target',
00101                 'target',
00102                 50,
00103                 $target
00104             ) . "\n";
00105 
00106         if ( !$wgMiserMode ) {
00107             $s .= Html::namespaceSelector(
00108                 array(
00109                     'selected' => $namespace,
00110                     'all' => '',
00111                     'label' => $this->msg( 'linksearch-ns' )->text()
00112                 ), array(
00113                     'name' => 'namespace',
00114                     'id' => 'namespace',
00115                     'class' => 'namespaceselector',
00116                 )
00117             );
00118         }
00119 
00120         $s .= Xml::submitButton( $this->msg( 'linksearch-ok' )->text() ) . "\n" .
00121             Html::closeElement( 'fieldset' ) . "\n" .
00122             Html::closeElement( 'form' ) . "\n";
00123         $out->addHTML( $s );
00124 
00125         if ( $target != '' ) {
00126             $this->setParams( array(
00127                 'query' => $target2,
00128                 'namespace' => $namespace,
00129                 'protocol' => $protocol ) );
00130             parent::execute( $par );
00131             if ( $this->mMungedQuery === false ) {
00132                 $out->addWikiMsg( 'linksearch-error' );
00133             }
00134         }
00135     }
00136 
00141     function isSyndicated() {
00142         return false;
00143     }
00144 
00152     static function mungeQuery( $query, $prot ) {
00153         $field = 'el_index';
00154         $rv = LinkFilter::makeLikeArray( $query, $prot );
00155         if ( $rv === false ) {
00156             // LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
00157             $pattern = '/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/';
00158             if ( preg_match( $pattern, $query ) ) {
00159                 $dbr = wfGetDB( DB_SLAVE );
00160                 $rv = array( $prot . rtrim( $query, " \t*" ), $dbr->anyString() );
00161                 $field = 'el_to';
00162             }
00163         }
00164 
00165         return array( $rv, $field );
00166     }
00167 
00168     function linkParameters() {
00169         global $wgMiserMode;
00170         $params = array();
00171         $params['target'] = $this->mProt . $this->mQuery;
00172         if ( isset( $this->mNs ) && !$wgMiserMode ) {
00173             $params['namespace'] = $this->mNs;
00174         }
00175 
00176         return $params;
00177     }
00178 
00179     function getQueryInfo() {
00180         global $wgMiserMode;
00181         $dbr = wfGetDB( DB_SLAVE );
00182         // strip everything past first wildcard, so that
00183         // index-based-only lookup would be done
00184         list( $this->mMungedQuery, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
00185         if ( $this->mMungedQuery === false ) {
00186             // Invalid query; return no results
00187             return array( 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' );
00188         }
00189 
00190         $stripped = LinkFilter::keepOneWildcard( $this->mMungedQuery );
00191         $like = $dbr->buildLike( $stripped );
00192         $retval = array(
00193             'tables' => array( 'page', 'externallinks' ),
00194             'fields' => array(
00195                 'namespace' => 'page_namespace',
00196                 'title' => 'page_title',
00197                 'value' => 'el_index',
00198                 'url' => 'el_to'
00199             ),
00200             'conds' => array(
00201                 'page_id = el_from',
00202                 "$clause $like"
00203             ),
00204             'options' => array( 'USE INDEX' => $clause )
00205         );
00206 
00207         if ( isset( $this->mNs ) && !$wgMiserMode ) {
00208             $retval['conds']['page_namespace'] = $this->mNs;
00209         }
00210 
00211         return $retval;
00212     }
00213 
00219     function formatResult( $skin, $result ) {
00220         $title = Title::makeTitle( $result->namespace, $result->title );
00221         $url = $result->url;
00222         $pageLink = Linker::linkKnown( $title );
00223         $urlLink = Linker::makeExternalLink( $url, $url );
00224 
00225         return $this->msg( 'linksearch-line' )->rawParams( $urlLink, $pageLink )->escaped();
00226     }
00227 
00231     function doQuery( $offset = false, $limit = false ) {
00232         list( $this->mMungedQuery, ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt );
00233         if ( $this->mMungedQuery === false ) {
00234             $this->getOutput()->addWikiMsg( 'linksearch-error' );
00235         } else {
00236             // For debugging
00237             // Generates invalid xhtml with patterns that contain --
00238             //$this->getOutput()->addHTML( "\n<!-- " . htmlspecialchars( $this->mMungedQuery ) . " -->\n" );
00239             parent::doQuery( $offset, $limit );
00240         }
00241     }
00242 
00250     function getOrderFields() {
00251         return array();
00252     }
00253 
00254     protected function getGroupName() {
00255         return 'redirects';
00256     }
00257 }