MediaWiki  REL1_23
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         global $wgUrlProtocols, $wgMiserMode, $wgScript;
00082 
00083         $this->initServices();
00084 
00085         $this->setHeaders();
00086         $this->outputHeader();
00087 
00088         $out = $this->getOutput();
00089         $out->allowClickjacking();
00090 
00091         $request = $this->getRequest();
00092         $target = $request->getVal( 'target', $par );
00093         $namespace = $request->getIntorNull( 'namespace', null );
00094 
00095         $protocols_list = array();
00096         foreach ( $wgUrlProtocols as $prot ) {
00097             if ( $prot !== '//' ) {
00098                 $protocols_list[] = $prot;
00099             }
00100         }
00101 
00102         $target2 = $target;
00103         // Get protocol, default is http://
00104         $protocol = 'http://';
00105         $bits = wfParseUrl( $target );
00106         if ( isset( $bits['scheme'] ) && isset( $bits['delimiter'] ) ) {
00107             $protocol = $bits['scheme'] . $bits['delimiter'];
00108             // Make sure wfParseUrl() didn't make some well-intended correction in the
00109             // protocol
00110             if ( strcasecmp( $protocol, substr( $target, 0, strlen( $protocol ) ) ) === 0 ) {
00111                 $target2 = substr( $target, strlen( $protocol ) );
00112             } else {
00113                 // If it did, let LinkFilter::makeLikeArray() handle this
00114                 $protocol = '';
00115             }
00116         }
00117 
00118         $out->addWikiMsg(
00119             'linksearch-text',
00120             '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
00121             count( $protocols_list )
00122         );
00123         $s = Html::openElement(
00124             'form',
00125             array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $wgScript )
00126         ) . "\n" .
00127             Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) . "\n" .
00128             Html::openElement( 'fieldset' ) . "\n" .
00129             Html::element( 'legend', array(), $this->msg( 'linksearch' )->text() ) . "\n" .
00130             Xml::inputLabel(
00131                 $this->msg( 'linksearch-pat' )->text(),
00132                 'target',
00133                 'target',
00134                 50,
00135                 $target
00136             ) . "\n";
00137 
00138         if ( !$wgMiserMode ) {
00139             $s .= Html::namespaceSelector(
00140                 array(
00141                     'selected' => $namespace,
00142                     'all' => '',
00143                     'label' => $this->msg( 'linksearch-ns' )->text()
00144                 ), array(
00145                     'name' => 'namespace',
00146                     'id' => 'namespace',
00147                     'class' => 'namespaceselector',
00148                 )
00149             );
00150         }
00151 
00152         $s .= Xml::submitButton( $this->msg( 'linksearch-ok' )->text() ) . "\n" .
00153             Html::closeElement( 'fieldset' ) . "\n" .
00154             Html::closeElement( 'form' ) . "\n";
00155         $out->addHTML( $s );
00156 
00157         if ( $target != '' ) {
00158             $this->setParams( array(
00159                 'query' => $target2,
00160                 'namespace' => $namespace,
00161                 'protocol' => $protocol ) );
00162             parent::execute( $par );
00163             if ( $this->mMungedQuery === false ) {
00164                 $out->addWikiMsg( 'linksearch-error' );
00165             }
00166         }
00167     }
00168 
00173     function isSyndicated() {
00174         return false;
00175     }
00176 
00185     static function mungeQuery( $query, $prot ) {
00186         $field = 'el_index';
00187         $dbr = wfGetDB( DB_SLAVE );
00188 
00189         if ( $query === '*' && $prot !== '' ) {
00190             // Allow queries like 'ftp://*' to find all ftp links
00191             $rv = array( $prot, $dbr->anyString() );
00192         } else {
00193             $rv = LinkFilter::makeLikeArray( $query, $prot );
00194         }
00195 
00196         if ( $rv === false ) {
00197             // LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
00198             $pattern = '/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/';
00199             if ( preg_match( $pattern, $query ) ) {
00200                 $rv = array( $prot . rtrim( $query, " \t*" ), $dbr->anyString() );
00201                 $field = 'el_to';
00202             }
00203         }
00204 
00205         return array( $rv, $field );
00206     }
00207 
00208     function linkParameters() {
00209         global $wgMiserMode;
00210         $params = array();
00211         $params['target'] = $this->mProt . $this->mQuery;
00212         if ( isset( $this->mNs ) && !$wgMiserMode ) {
00213             $params['namespace'] = $this->mNs;
00214         }
00215 
00216         return $params;
00217     }
00218 
00219     function getQueryInfo() {
00220         global $wgMiserMode;
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 ( isset( $this->mNs ) && !$wgMiserMode ) {
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 }