MediaWiki  REL1_24
SpecialLinkSearch.php
Go to the documentation of this file.
00001 <?php
00029 class LinkSearchPage extends QueryPage {
00030 
00034     protected $linkRenderer = null;
00035 
00036     function setParams( $params ) {
00037         $this->mQuery = $params['query'];
00038         $this->mNs = $params['namespace'];
00039         $this->mProt = $params['protocol'];
00040     }
00041 
00042     function __construct( $name = 'LinkSearch' ) {
00043         parent::__construct( $name );
00044 
00045         // Since we don't control the constructor parameters, we can't inject services that way.
00046         // Instead, we initialize services in the execute() method, and allow them to be overridden
00047         // using the setServices() method.
00048     }
00049 
00058     public function setPageLinkRenderer(
00059         PageLinkRenderer $linkRenderer
00060     ) {
00061         $this->linkRenderer = $linkRenderer;
00062     }
00063 
00068     private function initServices() {
00069         if ( !$this->linkRenderer ) {
00070             $lang = $this->getContext()->getLanguage();
00071             $titleFormatter = new MediaWikiTitleCodec( $lang, GenderCache::singleton() );
00072             $this->linkRenderer = new MediaWikiPageLinkRenderer( $titleFormatter );
00073         }
00074     }
00075 
00076     function isCacheable() {
00077         return false;
00078     }
00079 
00080     function execute( $par ) {
00081         $this->initServices();
00082 
00083         $this->setHeaders();
00084         $this->outputHeader();
00085 
00086         $out = $this->getOutput();
00087         $out->allowClickjacking();
00088 
00089         $request = $this->getRequest();
00090         $target = $request->getVal( 'target', $par );
00091         $namespace = $request->getIntorNull( 'namespace', null );
00092 
00093         $protocols_list = array();
00094         foreach ( $this->getConfig()->get( 'UrlProtocols' ) as $prot ) {
00095             if ( $prot !== '//' ) {
00096                 $protocols_list[] = $prot;
00097             }
00098         }
00099 
00100         $target2 = $target;
00101         // Get protocol, default is http://
00102         $protocol = 'http://';
00103         $bits = wfParseUrl( $target );
00104         if ( isset( $bits['scheme'] ) && isset( $bits['delimiter'] ) ) {
00105             $protocol = $bits['scheme'] . $bits['delimiter'];
00106             // Make sure wfParseUrl() didn't make some well-intended correction in the
00107             // protocol
00108             if ( strcasecmp( $protocol, substr( $target, 0, strlen( $protocol ) ) ) === 0 ) {
00109                 $target2 = substr( $target, strlen( $protocol ) );
00110             } else {
00111                 // If it did, let LinkFilter::makeLikeArray() handle this
00112                 $protocol = '';
00113             }
00114         }
00115 
00116         $out->addWikiMsg(
00117             'linksearch-text',
00118             '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
00119             count( $protocols_list )
00120         );
00121         $s = Html::openElement(
00122             'form',
00123             array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => wfScript() )
00124         ) . "\n" .
00125             Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) . "\n" .
00126             Html::openElement( 'fieldset' ) . "\n" .
00127             Html::element( 'legend', array(), $this->msg( 'linksearch' )->text() ) . "\n" .
00128             Xml::inputLabel(
00129                 $this->msg( 'linksearch-pat' )->text(),
00130                 'target',
00131                 'target',
00132                 50,
00133                 $target,
00134                 array(
00135                     // URLs are always ltr
00136                     'dir' => 'ltr',
00137                 )
00138             ) . "\n";
00139 
00140         if ( !$this->getConfig()->get( 'MiserMode' ) ) {
00141             $s .= Html::namespaceSelector(
00142                 array(
00143                     'selected' => $namespace,
00144                     'all' => '',
00145                     'label' => $this->msg( 'linksearch-ns' )->text()
00146                 ), array(
00147                     'name' => 'namespace',
00148                     'id' => 'namespace',
00149                     'class' => 'namespaceselector',
00150                 )
00151             );
00152         }
00153 
00154         $s .= Xml::submitButton( $this->msg( 'linksearch-ok' )->text() ) . "\n" .
00155             Html::closeElement( 'fieldset' ) . "\n" .
00156             Html::closeElement( 'form' ) . "\n";
00157         $out->addHTML( $s );
00158 
00159         if ( $target != '' ) {
00160             $this->setParams( array(
00161                 'query' => $target2,
00162                 'namespace' => $namespace,
00163                 'protocol' => $protocol ) );
00164             parent::execute( $par );
00165             if ( $this->mMungedQuery === false ) {
00166                 $out->addWikiMsg( 'linksearch-error' );
00167             }
00168         }
00169     }
00170 
00175     function isSyndicated() {
00176         return false;
00177     }
00178 
00187     static function mungeQuery( $query, $prot ) {
00188         $field = 'el_index';
00189         $dbr = wfGetDB( DB_SLAVE );
00190 
00191         if ( $query === '*' && $prot !== '' ) {
00192             // Allow queries like 'ftp://*' to find all ftp links
00193             $rv = array( $prot, $dbr->anyString() );
00194         } else {
00195             $rv = LinkFilter::makeLikeArray( $query, $prot );
00196         }
00197 
00198         if ( $rv === false ) {
00199             // LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
00200             $pattern = '/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/';
00201             if ( preg_match( $pattern, $query ) ) {
00202                 $rv = array( $prot . rtrim( $query, " \t*" ), $dbr->anyString() );
00203                 $field = 'el_to';
00204             }
00205         }
00206 
00207         return array( $rv, $field );
00208     }
00209 
00210     function linkParameters() {
00211         $params = array();
00212         $params['target'] = $this->mProt . $this->mQuery;
00213         if ( $this->mNs !== null && !$this->getConfig()->get( 'MiserMode' ) ) {
00214             $params['namespace'] = $this->mNs;
00215         }
00216 
00217         return $params;
00218     }
00219 
00220     function getQueryInfo() {
00221         $dbr = wfGetDB( DB_SLAVE );
00222         // strip everything past first wildcard, so that
00223         // index-based-only lookup would be done
00224         list( $this->mMungedQuery, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
00225         if ( $this->mMungedQuery === false ) {
00226             // Invalid query; return no results
00227             return array( 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' );
00228         }
00229 
00230         $stripped = LinkFilter::keepOneWildcard( $this->mMungedQuery );
00231         $like = $dbr->buildLike( $stripped );
00232         $retval = array(
00233             'tables' => array( 'page', 'externallinks' ),
00234             'fields' => array(
00235                 'namespace' => 'page_namespace',
00236                 'title' => 'page_title',
00237                 'value' => 'el_index',
00238                 'url' => 'el_to'
00239             ),
00240             'conds' => array(
00241                 'page_id = el_from',
00242                 "$clause $like"
00243             ),
00244             'options' => array( 'USE INDEX' => $clause )
00245         );
00246 
00247         if ( $this->mNs !== null && !$this->getConfig()->get( 'MiserMode' ) ) {
00248             $retval['conds']['page_namespace'] = $this->mNs;
00249         }
00250 
00251         return $retval;
00252     }
00253 
00259     function formatResult( $skin, $result ) {
00260         $title = new TitleValue( (int)$result->namespace, $result->title );
00261         $pageLink = $this->linkRenderer->renderHtmlLink( $title );
00262 
00263         $url = $result->url;
00264         $urlLink = Linker::makeExternalLink( $url, $url );
00265 
00266         return $this->msg( 'linksearch-line' )->rawParams( $urlLink, $pageLink )->escaped();
00267     }
00268 
00275     function doQuery( $offset = false, $limit = false ) {
00276         list( $this->mMungedQuery, ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt );
00277         if ( $this->mMungedQuery === false ) {
00278             $this->getOutput()->addWikiMsg( 'linksearch-error' );
00279         } else {
00280             // For debugging
00281             // Generates invalid xhtml with patterns that contain --
00282             //$this->getOutput()->addHTML( "\n<!-- " . htmlspecialchars( $this->mMungedQuery ) . " -->\n" );
00283             parent::doQuery( $offset, $limit );
00284         }
00285     }
00286 
00294     function getOrderFields() {
00295         return array();
00296     }
00297 
00298     protected function getGroupName() {
00299         return 'redirects';
00300     }
00301 }