Index: trunk/phase3/includes/LinkCache.php |
— | — | @@ -9,6 +9,7 @@ |
10 | 10 | // becomes incompatible with the new version. |
11 | 11 | /* private */ var $mClassVer = 4; |
12 | 12 | |
| 13 | + /* private */ var $mPageLinks; |
13 | 14 | /* private */ var $mGoodLinks, $mBadLinks; |
14 | 15 | /* private */ var $mForUpdate; |
15 | 16 | |
— | — | @@ -25,6 +26,7 @@ |
26 | 27 | |
27 | 28 | function __construct() { |
28 | 29 | $this->mForUpdate = false; |
| 30 | + $this->mPageLinks = array(); |
29 | 31 | $this->mGoodLinks = array(); |
30 | 32 | $this->mGoodLinkFields = array(); |
31 | 33 | $this->mBadLinks = array(); |
— | — | @@ -76,12 +78,14 @@ |
77 | 79 | $dbkey = $title->getPrefixedDbKey(); |
78 | 80 | $this->mGoodLinks[$dbkey] = $id; |
79 | 81 | $this->mGoodLinkFields[$dbkey] = array( 'length' => $len, 'redirect' => $redir ); |
| 82 | + $this->mPageLinks[$dbkey] = $title; |
80 | 83 | } |
81 | 84 | |
82 | 85 | public function addBadLinkObj( $title ) { |
83 | 86 | $dbkey = $title->getPrefixedDbKey(); |
84 | 87 | if ( ! $this->isBadLink( $dbkey ) ) { |
85 | 88 | $this->mBadLinks[$dbkey] = 1; |
| 89 | + $this->mPageLinks[$dbkey] = $title; |
86 | 90 | } |
87 | 91 | } |
88 | 92 | |
— | — | @@ -92,6 +96,7 @@ |
93 | 97 | /* obsolete, for old $wgLinkCacheMemcached stuff */ |
94 | 98 | public function clearLink( $title ) {} |
95 | 99 | |
| 100 | + public function getPageLinks() { return $this->mPageLinks; } |
96 | 101 | public function getGoodLinks() { return $this->mGoodLinks; } |
97 | 102 | public function getBadLinks() { return array_keys( $this->mBadLinks ); } |
98 | 103 | |
— | — | @@ -176,6 +181,7 @@ |
177 | 182 | * Clears cache |
178 | 183 | */ |
179 | 184 | public function clear() { |
| 185 | + $this->mPageLinks = array(); |
180 | 186 | $this->mGoodLinks = array(); |
181 | 187 | $this->mGoodLinkFields = array(); |
182 | 188 | $this->mBadLinks = array(); |
Index: trunk/phase3/includes/parser/LinkHolderArray.php |
— | — | @@ -1,406 +0,0 @@ |
2 | | -<?php |
3 | | - |
4 | | -class LinkHolderArray { |
5 | | - var $batchSize = 1000; |
6 | | - |
7 | | - var $internals = array(), $interwikis = array(); |
8 | | - var $size = 0; |
9 | | - var $parent; |
10 | | - |
11 | | - function __construct( $parent ) { |
12 | | - $this->parent = $parent; |
13 | | - } |
14 | | - |
15 | | - /** |
16 | | - * Merge another LinkHolderArray into this one |
17 | | - */ |
18 | | - function merge( $other ) { |
19 | | - foreach ( $other->internals as $ns => $entries ) { |
20 | | - $this->size += count( $entries ); |
21 | | - if ( !isset( $this->internals[$ns] ) ) { |
22 | | - $this->internals[$ns] = $entries; |
23 | | - } else { |
24 | | - $this->internals[$ns] += $entries; |
25 | | - } |
26 | | - } |
27 | | - $this->interwikis += $other->interwikis; |
28 | | - } |
29 | | - |
30 | | - /** |
31 | | - * Returns true if the memory requirements of this object are getting large |
32 | | - */ |
33 | | - function isBig() { |
34 | | - return $this->size > $this->batchSize; |
35 | | - } |
36 | | - |
37 | | - /** |
38 | | - * Clear all stored link holders. |
39 | | - * Make sure you don't have any text left using these link holders, before you call this |
40 | | - */ |
41 | | - function clear() { |
42 | | - $this->internals = array(); |
43 | | - $this->interwikis = array(); |
44 | | - $this->size = 0; |
45 | | - } |
46 | | - |
47 | | - /** |
48 | | - * Make a link placeholder. The text returned can be later resolved to a real link with |
49 | | - * replaceLinkHolders(). This is done for two reasons: firstly to avoid further |
50 | | - * parsing of interwiki links, and secondly to allow all existence checks and |
51 | | - * article length checks (for stub links) to be bundled into a single query. |
52 | | - * |
53 | | - */ |
54 | | - function makeHolder( $nt, $text = '', $query = '', $trail = '', $prefix = '' ) { |
55 | | - wfProfileIn( __METHOD__ ); |
56 | | - if ( ! is_object($nt) ) { |
57 | | - # Fail gracefully |
58 | | - $retVal = "<!-- ERROR -->{$prefix}{$text}{$trail}"; |
59 | | - } else { |
60 | | - # Separate the link trail from the rest of the link |
61 | | - list( $inside, $trail ) = Linker::splitTrail( $trail ); |
62 | | - |
63 | | - $entry = array( |
64 | | - 'title' => $nt, |
65 | | - 'text' => $prefix.$text.$inside, |
66 | | - 'pdbk' => $nt->getPrefixedDBkey(), |
67 | | - ); |
68 | | - if ( $query !== '' ) { |
69 | | - $entry['query'] = $query; |
70 | | - } |
71 | | - |
72 | | - if ( $nt->isExternal() ) { |
73 | | - // Use a globally unique ID to keep the objects mergable |
74 | | - $key = $this->parent->nextLinkID(); |
75 | | - $this->interwikis['titles'][$key] = $entry; |
76 | | - $retVal = "<!--IWLINK $key-->{$trail}"; |
77 | | - } else { |
78 | | - $key = $this->parent->nextLinkID(); |
79 | | - $ns = $nt->getNamespace(); |
80 | | - $this->internals[$ns][$key] = $entry; |
81 | | - $retVal = "<!--LINK $ns:$key-->{$trail}"; |
82 | | - } |
83 | | - $this->size++; |
84 | | - } |
85 | | - wfProfileOut( __METHOD__ ); |
86 | | - return $retVal; |
87 | | - } |
88 | | - |
89 | | - /** |
90 | | - * Replace <!--LINK--> link placeholders with actual links, in the buffer |
91 | | - * Placeholders created in Skin::makeLinkObj() |
92 | | - * Returns an array of link CSS classes, indexed by PDBK. |
93 | | - */ |
94 | | - function replace( &$text ) { |
95 | | - wfProfileIn( __METHOD__ ); |
96 | | - |
97 | | - $colours = $this->replaceInternal( $text ); |
98 | | - $this->replaceInterwiki( $text ); |
99 | | - |
100 | | - wfProfileOut( __METHOD__ ); |
101 | | - return $colours; |
102 | | - } |
103 | | - |
104 | | - /** |
105 | | - * Replace internal links |
106 | | - */ |
107 | | - protected function replaceInternal( &$text ) { |
108 | | - if ( !$this->internals ) { |
109 | | - return; |
110 | | - } |
111 | | - |
112 | | - wfProfileIn( __METHOD__ ); |
113 | | - global $wgUser, $wgContLang; |
114 | | - |
115 | | - $pdbks = array(); |
116 | | - $colours = array(); |
117 | | - $linkcolour_ids = array(); |
118 | | - $sk = $this->parent->getOptions()->getSkin(); |
119 | | - $linkCache = LinkCache::singleton(); |
120 | | - $output = $this->parent->getOutput(); |
121 | | - |
122 | | - wfProfileIn( __METHOD__.'-check' ); |
123 | | - $dbr = wfGetDB( DB_SLAVE ); |
124 | | - $page = $dbr->tableName( 'page' ); |
125 | | - $threshold = $wgUser->getOption('stubthreshold'); |
126 | | - |
127 | | - # Sort by namespace |
128 | | - ksort( $this->internals ); |
129 | | - |
130 | | - # Generate query |
131 | | - $query = false; |
132 | | - $current = null; |
133 | | - foreach ( $this->internals as $ns => $entries ) { |
134 | | - foreach ( $entries as $index => $entry ) { |
135 | | - $key = "$ns:$index"; |
136 | | - $title = $entry['title']; |
137 | | - $pdbk = $entry['pdbk']; |
138 | | - |
139 | | - # Skip invalid entries. |
140 | | - # Result will be ugly, but prevents crash. |
141 | | - if ( is_null( $title ) ) { |
142 | | - continue; |
143 | | - } |
144 | | - |
145 | | - # Check if it's a static known link, e.g. interwiki |
146 | | - if ( $title->isAlwaysKnown() ) { |
147 | | - $colours[$pdbk] = ''; |
148 | | - } elseif ( ( $id = $linkCache->getGoodLinkID( $pdbk ) ) != 0 ) { |
149 | | - $colours[$pdbk] = ''; |
150 | | - $output->addLink( $title, $id ); |
151 | | - } elseif ( $linkCache->isBadLink( $pdbk ) ) { |
152 | | - $colours[$pdbk] = 'new'; |
153 | | - } elseif ( $title->getNamespace() == NS_SPECIAL && !SpecialPage::exists( $pdbk ) ) { |
154 | | - $colours[$pdbk] = 'new'; |
155 | | - } else { |
156 | | - # Not in the link cache, add it to the query |
157 | | - if ( !isset( $current ) ) { |
158 | | - $current = $ns; |
159 | | - $query = "SELECT page_id, page_namespace, page_title, page_is_redirect, page_len"; |
160 | | - $query .= " FROM $page WHERE (page_namespace=$ns AND page_title IN("; |
161 | | - } elseif ( $current != $ns ) { |
162 | | - $current = $ns; |
163 | | - $query .= ")) OR (page_namespace=$ns AND page_title IN("; |
164 | | - } else { |
165 | | - $query .= ', '; |
166 | | - } |
167 | | - |
168 | | - $query .= $dbr->addQuotes( $title->getDBkey() ); |
169 | | - } |
170 | | - } |
171 | | - } |
172 | | - if ( $query ) { |
173 | | - $query .= '))'; |
174 | | - |
175 | | - $res = $dbr->query( $query, __METHOD__ ); |
176 | | - |
177 | | - # Fetch data and form into an associative array |
178 | | - # non-existent = broken |
179 | | - while ( $s = $dbr->fetchObject($res) ) { |
180 | | - $title = Title::makeTitle( $s->page_namespace, $s->page_title ); |
181 | | - $pdbk = $title->getPrefixedDBkey(); |
182 | | - $linkCache->addGoodLinkObj( $s->page_id, $title, $s->page_len, $s->page_is_redirect ); |
183 | | - $output->addLink( $title, $s->page_id ); |
184 | | - $colours[$pdbk] = $sk->getLinkColour( $title, $threshold ); |
185 | | - //add id to the extension todolist |
186 | | - $linkcolour_ids[$s->page_id] = $pdbk; |
187 | | - } |
188 | | - unset( $res ); |
189 | | - //pass an array of page_ids to an extension |
190 | | - wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) ); |
191 | | - } |
192 | | - wfProfileOut( __METHOD__.'-check' ); |
193 | | - |
194 | | - # Do a second query for different language variants of links and categories |
195 | | - if($wgContLang->hasVariants()){ |
196 | | - $linkBatch = new LinkBatch(); |
197 | | - $variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders) |
198 | | - $categoryMap = array(); // maps $category_variant => $category (dbkeys) |
199 | | - $varCategories = array(); // category replacements oldDBkey => newDBkey |
200 | | - |
201 | | - $categories = $output->getCategoryLinks(); |
202 | | - |
203 | | - // Add variants of links to link batch |
204 | | - foreach ( $this->internals as $ns => $entries ) { |
205 | | - foreach ( $entries as $index => $entry ) { |
206 | | - $key = "$ns:$index"; |
207 | | - $pdbk = $entry['pdbk']; |
208 | | - $title = $entry['title']; |
209 | | - $titleText = $title->getText(); |
210 | | - |
211 | | - // generate all variants of the link title text |
212 | | - $allTextVariants = $wgContLang->convertLinkToAllVariants($titleText); |
213 | | - |
214 | | - // if link was not found (in first query), add all variants to query |
215 | | - if ( !isset($colours[$pdbk]) ){ |
216 | | - foreach($allTextVariants as $textVariant){ |
217 | | - if($textVariant != $titleText){ |
218 | | - $variantTitle = Title::makeTitle( $ns, $textVariant ); |
219 | | - if(is_null($variantTitle)) continue; |
220 | | - $linkBatch->addObj( $variantTitle ); |
221 | | - $variantMap[$variantTitle->getPrefixedDBkey()][] = $key; |
222 | | - } |
223 | | - } |
224 | | - } |
225 | | - } |
226 | | - } |
227 | | - |
228 | | - // process categories, check if a category exists in some variant |
229 | | - foreach( $categories as $category ){ |
230 | | - $variants = $wgContLang->convertLinkToAllVariants($category); |
231 | | - foreach($variants as $variant){ |
232 | | - if($variant != $category){ |
233 | | - $variantTitle = Title::newFromDBkey( Title::makeName(NS_CATEGORY,$variant) ); |
234 | | - if(is_null($variantTitle)) continue; |
235 | | - $linkBatch->addObj( $variantTitle ); |
236 | | - $categoryMap[$variant] = $category; |
237 | | - } |
238 | | - } |
239 | | - } |
240 | | - |
241 | | - |
242 | | - if(!$linkBatch->isEmpty()){ |
243 | | - // construct query |
244 | | - $titleClause = $linkBatch->constructSet('page', $dbr); |
245 | | - |
246 | | - $variantQuery = "SELECT page_id, page_namespace, page_title, page_is_redirect, page_len"; |
247 | | - |
248 | | - $variantQuery .= " FROM $page WHERE $titleClause"; |
249 | | - |
250 | | - $varRes = $dbr->query( $variantQuery, __METHOD__ ); |
251 | | - |
252 | | - // for each found variants, figure out link holders and replace |
253 | | - while ( $s = $dbr->fetchObject($varRes) ) { |
254 | | - |
255 | | - $variantTitle = Title::makeTitle( $s->page_namespace, $s->page_title ); |
256 | | - $varPdbk = $variantTitle->getPrefixedDBkey(); |
257 | | - $vardbk = $variantTitle->getDBkey(); |
258 | | - |
259 | | - $holderKeys = array(); |
260 | | - if(isset($variantMap[$varPdbk])){ |
261 | | - $holderKeys = $variantMap[$varPdbk]; |
262 | | - $linkCache->addGoodLinkObj( $s->page_id, $variantTitle, $s->page_len, $s->page_is_redirect ); |
263 | | - $output->addLink( $variantTitle, $s->page_id ); |
264 | | - } |
265 | | - |
266 | | - // loop over link holders |
267 | | - foreach($holderKeys as $key){ |
268 | | - list( $ns, $index ) = explode( ':', $key, 2 ); |
269 | | - $entry =& $this->internals[$ns][$index]; |
270 | | - $pdbk = $entry['pdbk']; |
271 | | - |
272 | | - if(!isset($colours[$pdbk])){ |
273 | | - // found link in some of the variants, replace the link holder data |
274 | | - $entry['title'] = $variantTitle; |
275 | | - $entry['pdbk'] = $varPdbk; |
276 | | - |
277 | | - // set pdbk and colour |
278 | | - $colours[$varPdbk] = $sk->getLinkColour( $variantTitle, $threshold ); |
279 | | - $linkcolour_ids[$s->page_id] = $pdbk; |
280 | | - } |
281 | | - wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) ); |
282 | | - } |
283 | | - |
284 | | - // check if the object is a variant of a category |
285 | | - if(isset($categoryMap[$vardbk])){ |
286 | | - $oldkey = $categoryMap[$vardbk]; |
287 | | - if($oldkey != $vardbk) |
288 | | - $varCategories[$oldkey]=$vardbk; |
289 | | - } |
290 | | - } |
291 | | - |
292 | | - // rebuild the categories in original order (if there are replacements) |
293 | | - if(count($varCategories)>0){ |
294 | | - $newCats = array(); |
295 | | - $originalCats = $output->getCategories(); |
296 | | - foreach($originalCats as $cat => $sortkey){ |
297 | | - // make the replacement |
298 | | - if( array_key_exists($cat,$varCategories) ) |
299 | | - $newCats[$varCategories[$cat]] = $sortkey; |
300 | | - else $newCats[$cat] = $sortkey; |
301 | | - } |
302 | | - $this->mOutput->parent->setCategoryLinks($newCats); |
303 | | - } |
304 | | - } |
305 | | - } |
306 | | - |
307 | | - # Construct search and replace arrays |
308 | | - wfProfileIn( __METHOD__.'-construct' ); |
309 | | - $replacePairs = array(); |
310 | | - foreach ( $this->internals as $ns => $entries ) { |
311 | | - foreach ( $entries as $index => $entry ) { |
312 | | - $pdbk = $entry['pdbk']; |
313 | | - $title = $entry['title']; |
314 | | - $query = isset( $entry['query'] ) ? $entry['query'] : ''; |
315 | | - $key = "$ns:$index"; |
316 | | - $searchkey = "<!--LINK $key-->"; |
317 | | - if ( !isset( $colours[$pdbk] ) || $colours[$pdbk] == 'new' ) { |
318 | | - $linkCache->addBadLinkObj( $title ); |
319 | | - $colours[$pdbk] = 'new'; |
320 | | - $output->addLink( $title, 0 ); |
321 | | - $replacePairs[$searchkey] = $sk->makeBrokenLinkObj( $title, |
322 | | - $entry['text'], |
323 | | - $query ); |
324 | | - } else { |
325 | | - $replacePairs[$searchkey] = $sk->makeColouredLinkObj( $title, $colours[$pdbk], |
326 | | - $entry['text'], |
327 | | - $query ); |
328 | | - } |
329 | | - } |
330 | | - } |
331 | | - $replacer = new HashtableReplacer( $replacePairs, 1 ); |
332 | | - wfProfileOut( __METHOD__.'-construct' ); |
333 | | - |
334 | | - # Do the thing |
335 | | - wfProfileIn( __METHOD__.'-replace' ); |
336 | | - $text = preg_replace_callback( |
337 | | - '/(<!--LINK .*?-->)/', |
338 | | - $replacer->cb(), |
339 | | - $text); |
340 | | - |
341 | | - wfProfileOut( __METHOD__.'-replace' ); |
342 | | - wfProfileOut( __METHOD__ ); |
343 | | - } |
344 | | - |
345 | | - /** |
346 | | - * Replace interwiki links |
347 | | - */ |
348 | | - protected function replaceInterwiki( &$text ) { |
349 | | - if ( empty( $this->mInterwikiLinkHolders['texts'] ) ) { |
350 | | - return; |
351 | | - } |
352 | | - |
353 | | - wfProfileIn( __METHOD__ ); |
354 | | - # Make interwiki link HTML |
355 | | - $replacePairs = array(); |
356 | | - foreach( $this->mInterwikiLinkHolders['texts'] as $key => $link ) { |
357 | | - $title = $this->mInterwikiLinkHolders['titles'][$key]; |
358 | | - $replacePairs[$key] = $sk->link( $title, $link ); |
359 | | - } |
360 | | - $replacer = new HashtableReplacer( $replacePairs, 1 ); |
361 | | - |
362 | | - $text = preg_replace_callback( |
363 | | - '/<!--IWLINK (.*?)-->/', |
364 | | - $replacer->cb(), |
365 | | - $text ); |
366 | | - wfProfileOut( __METHOD__ ); |
367 | | - } |
368 | | - |
369 | | - /** |
370 | | - * Replace <!--LINK--> link placeholders with plain text of links |
371 | | - * (not HTML-formatted). |
372 | | - * @param string $text |
373 | | - * @return string |
374 | | - */ |
375 | | - function replaceText( $text ) { |
376 | | - wfProfileIn( __METHOD__ ); |
377 | | - |
378 | | - $text = preg_replace_callback( |
379 | | - '/<!--(LINK|IWLINK) (.*?)-->/', |
380 | | - array( &$this, 'replaceTextCallback' ), |
381 | | - $text ); |
382 | | - |
383 | | - wfProfileOut( __METHOD__ ); |
384 | | - return $text; |
385 | | - } |
386 | | - |
387 | | - /** |
388 | | - * @param array $matches |
389 | | - * @return string |
390 | | - * @private |
391 | | - */ |
392 | | - function replaceTextCallback( $matches ) { |
393 | | - $type = $matches[1]; |
394 | | - $key = $matches[2]; |
395 | | - if( $type == 'LINK' ) { |
396 | | - list( $ns, $index ) = explode( ':', $key, 2 ); |
397 | | - if( isset( $this->internals[$ns][$index]['text'] ) ) { |
398 | | - return $this->internals[$ns][$index]['text']; |
399 | | - } |
400 | | - } elseif( $type == 'IWLINK' ) { |
401 | | - if( isset( $this->interwikis[$key]['text'] ) ) { |
402 | | - return $this->interwikis[$key]['text']; |
403 | | - } |
404 | | - } |
405 | | - return $matches[0]; |
406 | | - } |
407 | | -} |
Index: trunk/phase3/includes/parser/Parser.php |
— | — | @@ -98,7 +98,7 @@ |
99 | 99 | # Cleared with clearState(): |
100 | 100 | var $mOutput, $mAutonumber, $mDTopen, $mStripState; |
101 | 101 | var $mIncludeCount, $mArgStack, $mLastSection, $mInPre; |
102 | | - var $mInterwikiLinkHolders, $mLinkHolders, $mLinkID; |
| 102 | + var $mInterwikiLinkHolders, $mLinkHolders; |
103 | 103 | var $mIncludeSizes, $mPPNodeCount, $mDefaultSort; |
104 | 104 | var $mTplExpandCache; // empty-frame expansion cache |
105 | 105 | var $mTplRedirCache, $mTplDomCache, $mHeadings, $mDoubleUnderscores; |
— | — | @@ -179,8 +179,17 @@ |
180 | 180 | $this->mStripState = new StripState; |
181 | 181 | $this->mArgStack = false; |
182 | 182 | $this->mInPre = false; |
183 | | - $this->mLinkHolders = new LinkHolderArray( $this ); |
184 | | - $this->mLinkID = 0; |
| 183 | + $this->mInterwikiLinkHolders = array( |
| 184 | + 'texts' => array(), |
| 185 | + 'titles' => array() |
| 186 | + ); |
| 187 | + $this->mLinkHolders = array( |
| 188 | + 'namespaces' => array(), |
| 189 | + 'dbkeys' => array(), |
| 190 | + 'queries' => array(), |
| 191 | + 'texts' => array(), |
| 192 | + 'titles' => array() |
| 193 | + ); |
185 | 194 | $this->mRevisionTimestamp = $this->mRevisionId = null; |
186 | 195 | |
187 | 196 | /** |
— | — | @@ -195,7 +204,7 @@ |
196 | 205 | */ |
197 | 206 | #$this->mUniqPrefix = "\x07UNIQ" . Parser::getRandomString(); |
198 | 207 | # Changed to \x7f to allow XML double-parsing -- TS |
199 | | - $this->mUniqPrefix = "\x7fUNIQ" . self::getRandomString(); |
| 208 | + $this->mUniqPrefix = "\x7fUNIQ" . Parser::getRandomString(); |
200 | 209 | |
201 | 210 | |
202 | 211 | # Clear these on every parse, bug 4549 |
— | — | @@ -285,7 +294,7 @@ |
286 | 295 | */ |
287 | 296 | |
288 | 297 | global $wgUseTidy, $wgAlwaysUseTidy, $wgContLang; |
289 | | - $fname = __METHOD__.'-' . wfGetCaller(); |
| 298 | + $fname = 'Parser::parse-' . wfGetCaller(); |
290 | 299 | wfProfileIn( __METHOD__ ); |
291 | 300 | wfProfileIn( $fname ); |
292 | 301 | |
— | — | @@ -319,6 +328,7 @@ |
320 | 329 | ); |
321 | 330 | $text = preg_replace( array_keys($fixtags), array_values($fixtags), $text ); |
322 | 331 | |
| 332 | + # only once and last |
323 | 333 | $text = $this->doBlockLevels( $text, $linestart ); |
324 | 334 | |
325 | 335 | $this->replaceLinkHolders( $text ); |
— | — | @@ -338,7 +348,7 @@ |
339 | 349 | $uniq_prefix = $this->mUniqPrefix; |
340 | 350 | $matches = array(); |
341 | 351 | $elements = array_keys( $this->mTransparentTagHooks ); |
342 | | - $text = self::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); |
| 352 | + $text = Parser::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); |
343 | 353 | |
344 | 354 | foreach( $matches as $marker => $data ) { |
345 | 355 | list( $element, $content, $params, $tag ) = $data; |
— | — | @@ -356,7 +366,7 @@ |
357 | 367 | $text = Sanitizer::normalizeCharReferences( $text ); |
358 | 368 | |
359 | 369 | if (($wgUseTidy and $this->mOptions->mTidy) or $wgAlwaysUseTidy) { |
360 | | - $text = self::tidy($text); |
| 370 | + $text = Parser::tidy($text); |
361 | 371 | } else { |
362 | 372 | # attempt to sanitize at least some nesting problems |
363 | 373 | # (bug #2702 and quite a few others) |
— | — | @@ -461,8 +471,6 @@ |
462 | 472 | function &getTitle() { return $this->mTitle; } |
463 | 473 | function getOptions() { return $this->mOptions; } |
464 | 474 | function getRevisionId() { return $this->mRevisionId; } |
465 | | - function getOutput() { return $this->mOutput; } |
466 | | - function nextLinkID() { return $this->mLinkID++; } |
467 | 475 | |
468 | 476 | function getFunctionLang() { |
469 | 477 | global $wgLang, $wgContLang; |
— | — | @@ -650,9 +658,9 @@ |
651 | 659 | ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>'. |
652 | 660 | '<head><title>test</title></head><body>'.$text.'</body></html>'; |
653 | 661 | if( $wgTidyInternal ) { |
654 | | - $correctedtext = self::internalTidy( $wrappedtext ); |
| 662 | + $correctedtext = Parser::internalTidy( $wrappedtext ); |
655 | 663 | } else { |
656 | | - $correctedtext = self::externalTidy( $wrappedtext ); |
| 664 | + $correctedtext = Parser::externalTidy( $wrappedtext ); |
657 | 665 | } |
658 | 666 | if( is_null( $correctedtext ) ) { |
659 | 667 | wfDebug( "Tidy error detected!\n" ); |
— | — | @@ -669,7 +677,8 @@ |
670 | 678 | */ |
671 | 679 | function externalTidy( $text ) { |
672 | 680 | global $wgTidyConf, $wgTidyBin, $wgTidyOpts; |
673 | | - wfProfileIn( __METHOD__ ); |
| 681 | + $fname = 'Parser::externalTidy'; |
| 682 | + wfProfileIn( $fname ); |
674 | 683 | |
675 | 684 | $cleansource = ''; |
676 | 685 | $opts = ' -utf8'; |
— | — | @@ -698,7 +707,7 @@ |
699 | 708 | } |
700 | 709 | } |
701 | 710 | |
702 | | - wfProfileOut( __METHOD__ ); |
| 711 | + wfProfileOut( $fname ); |
703 | 712 | |
704 | 713 | if( $cleansource == '' && $text != '') { |
705 | 714 | // Some kind of error happened, so we couldn't get the corrected text. |
— | — | @@ -720,7 +729,8 @@ |
721 | 730 | */ |
722 | 731 | function internalTidy( $text ) { |
723 | 732 | global $wgTidyConf, $IP, $wgDebugTidy; |
724 | | - wfProfileIn( __METHOD__ ); |
| 733 | + $fname = 'Parser::internalTidy'; |
| 734 | + wfProfileIn( $fname ); |
725 | 735 | |
726 | 736 | $tidy = new tidy; |
727 | 737 | $tidy->parseString( $text, $wgTidyConf, 'utf8' ); |
— | — | @@ -738,7 +748,7 @@ |
739 | 749 | "\n-->"; |
740 | 750 | } |
741 | 751 | |
742 | | - wfProfileOut( __METHOD__ ); |
| 752 | + wfProfileOut( $fname ); |
743 | 753 | return $cleansource; |
744 | 754 | } |
745 | 755 | |
— | — | @@ -748,35 +758,34 @@ |
749 | 759 | * @private |
750 | 760 | */ |
751 | 761 | function doTableStuff ( $text ) { |
752 | | - wfProfileIn( __METHOD__ ); |
| 762 | + $fname = 'Parser::doTableStuff'; |
| 763 | + wfProfileIn( $fname ); |
753 | 764 | |
754 | | - $lines = StringUtils::explode( "\n", $text ); |
755 | | - $out = ''; |
| 765 | + $lines = explode ( "\n" , $text ); |
756 | 766 | $td_history = array (); // Is currently a td tag open? |
757 | 767 | $last_tag_history = array (); // Save history of last lag activated (td, th or caption) |
758 | 768 | $tr_history = array (); // Is currently a tr tag open? |
759 | 769 | $tr_attributes = array (); // history of tr attributes |
760 | 770 | $has_opened_tr = array(); // Did this table open a <tr> element? |
761 | 771 | $indent_level = 0; // indent level of the table |
| 772 | + foreach ( $lines as $key => $line ) |
| 773 | + { |
| 774 | + $line = trim ( $line ); |
762 | 775 | |
763 | | - foreach ( $lines as $outLine ) { |
764 | | - $line = trim( $outLine ); |
765 | | - |
766 | 776 | if( $line == '' ) { // empty line, go to next line |
767 | | - $out .= "\n"; |
768 | 777 | continue; |
769 | 778 | } |
770 | | - $first_character = $line[0]; |
| 779 | + $first_character = $line{0}; |
771 | 780 | $matches = array(); |
772 | 781 | |
773 | | - if ( preg_match( '/^(:*)\{\|(.*)$/', $line , $matches ) ) { |
| 782 | + if ( preg_match( '/^(:*)\{\|(.*)$/' , $line , $matches ) ) { |
774 | 783 | // First check if we are starting a new table |
775 | 784 | $indent_level = strlen( $matches[1] ); |
776 | 785 | |
777 | 786 | $attributes = $this->mStripState->unstripBoth( $matches[2] ); |
778 | 787 | $attributes = Sanitizer::fixTagAttributes ( $attributes , 'table' ); |
779 | 788 | |
780 | | - $outLine = str_repeat( '<dl><dd>' , $indent_level ) . "<table{$attributes}>"; |
| 789 | + $lines[$key] = str_repeat( '<dl><dd>' , $indent_level ) . "<table{$attributes}>"; |
781 | 790 | array_push ( $td_history , false ); |
782 | 791 | array_push ( $last_tag_history , '' ); |
783 | 792 | array_push ( $tr_history , false ); |
— | — | @@ -784,7 +793,6 @@ |
785 | 794 | array_push ( $has_opened_tr , false ); |
786 | 795 | } else if ( count ( $td_history ) == 0 ) { |
787 | 796 | // Don't do any of the following |
788 | | - $out .= $outLine."\n"; |
789 | 797 | continue; |
790 | 798 | } else if ( substr ( $line , 0 , 2 ) == '|}' ) { |
791 | 799 | // We are ending a table |
— | — | @@ -803,7 +811,7 @@ |
804 | 812 | $line = "</{$last_tag}>{$line}"; |
805 | 813 | } |
806 | 814 | array_pop ( $tr_attributes ); |
807 | | - $outLine = $line . str_repeat( '</dd></dl>' , $indent_level ); |
| 815 | + $lines[$key] = $line . str_repeat( '</dd></dl>' , $indent_level ); |
808 | 816 | } else if ( substr ( $line , 0 , 2 ) == '|-' ) { |
809 | 817 | // Now we have a table row |
810 | 818 | $line = preg_replace( '#^\|-+#', '', $line ); |
— | — | @@ -827,7 +835,7 @@ |
828 | 836 | $line = "</{$last_tag}>{$line}"; |
829 | 837 | } |
830 | 838 | |
831 | | - $outLine = $line; |
| 839 | + $lines[$key] = $line; |
832 | 840 | array_push ( $tr_history , false ); |
833 | 841 | array_push ( $td_history , false ); |
834 | 842 | array_push ( $last_tag_history , '' ); |
— | — | @@ -851,7 +859,7 @@ |
852 | 860 | // attribute values containing literal "||". |
853 | 861 | $cells = StringUtils::explodeMarkup( '||' , $line ); |
854 | 862 | |
855 | | - $outLine = ''; |
| 863 | + $lines[$key] = ''; |
856 | 864 | |
857 | 865 | // Loop through each table cell |
858 | 866 | foreach ( $cells as $cell ) |
— | — | @@ -902,42 +910,38 @@ |
903 | 911 | $cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[1]}"; |
904 | 912 | } |
905 | 913 | |
906 | | - $outLine .= $cell; |
| 914 | + $lines[$key] .= $cell; |
907 | 915 | array_push ( $td_history , true ); |
908 | 916 | } |
909 | 917 | } |
910 | | - $out .= $outLine . "\n"; |
911 | 918 | } |
912 | 919 | |
913 | 920 | // Closing open td, tr && table |
914 | 921 | while ( count ( $td_history ) > 0 ) |
915 | 922 | { |
916 | 923 | if ( array_pop ( $td_history ) ) { |
917 | | - $out .= "</td>\n"; |
| 924 | + $lines[] = '</td>' ; |
918 | 925 | } |
919 | 926 | if ( array_pop ( $tr_history ) ) { |
920 | | - $out .= "</tr>\n"; |
| 927 | + $lines[] = '</tr>' ; |
921 | 928 | } |
922 | 929 | if ( !array_pop ( $has_opened_tr ) ) { |
923 | | - $out .= "<tr><td></td></tr>\n" ; |
| 930 | + $lines[] = "<tr><td></td></tr>" ; |
924 | 931 | } |
925 | 932 | |
926 | | - $out .= "</table>\n"; |
| 933 | + $lines[] = '</table>' ; |
927 | 934 | } |
928 | 935 | |
929 | | - // Remove trailing line-ending (b/c) |
930 | | - if ( substr( $out, -1 ) == "\n" ) { |
931 | | - $out = substr( $out, 0, -1 ); |
932 | | - } |
| 936 | + $output = implode ( "\n" , $lines ) ; |
933 | 937 | |
934 | 938 | // special case: don't return empty table |
935 | | - if( $out == "<table>\n<tr><td></td></tr>\n</table>" ) { |
936 | | - $out = ''; |
| 939 | + if( $output == "<table>\n<tr><td></td></tr>\n</table>" ) { |
| 940 | + $output = ''; |
937 | 941 | } |
938 | 942 | |
939 | | - wfProfileOut( __METHOD__ ); |
| 943 | + wfProfileOut( $fname ); |
940 | 944 | |
941 | | - return $out; |
| 945 | + return $output; |
942 | 946 | } |
943 | 947 | |
944 | 948 | /** |
— | — | @@ -948,11 +952,12 @@ |
949 | 953 | */ |
950 | 954 | function internalParse( $text ) { |
951 | 955 | $isMain = true; |
952 | | - wfProfileIn( __METHOD__ ); |
| 956 | + $fname = 'Parser::internalParse'; |
| 957 | + wfProfileIn( $fname ); |
953 | 958 | |
954 | 959 | # Hook to suspend the parser in this state |
955 | 960 | if ( !wfRunHooks( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) { |
956 | | - wfProfileOut( __METHOD__ ); |
| 961 | + wfProfileOut( $fname ); |
957 | 962 | return $text ; |
958 | 963 | } |
959 | 964 | |
— | — | @@ -985,7 +990,7 @@ |
986 | 991 | $text = $this->doMagicLinks( $text ); |
987 | 992 | $text = $this->formatHeadings( $text, $isMain ); |
988 | 993 | |
989 | | - wfProfileOut( __METHOD__ ); |
| 994 | + wfProfileOut( $fname ); |
990 | 995 | return $text; |
991 | 996 | } |
992 | 997 | |
— | — | @@ -1055,13 +1060,14 @@ |
1056 | 1061 | * @private |
1057 | 1062 | */ |
1058 | 1063 | function doHeadings( $text ) { |
1059 | | - wfProfileIn( __METHOD__ ); |
| 1064 | + $fname = 'Parser::doHeadings'; |
| 1065 | + wfProfileIn( $fname ); |
1060 | 1066 | for ( $i = 6; $i >= 1; --$i ) { |
1061 | 1067 | $h = str_repeat( '=', $i ); |
1062 | 1068 | $text = preg_replace( "/^$h(.+)$h\\s*$/m", |
1063 | 1069 | "<h$i>\\1</h$i>", $text ); |
1064 | 1070 | } |
1065 | | - wfProfileOut( __METHOD__ ); |
| 1071 | + wfProfileOut( $fname ); |
1066 | 1072 | return $text; |
1067 | 1073 | } |
1068 | 1074 | |
— | — | @@ -1071,14 +1077,15 @@ |
1072 | 1078 | * @return string the altered text |
1073 | 1079 | */ |
1074 | 1080 | function doAllQuotes( $text ) { |
1075 | | - wfProfileIn( __METHOD__ ); |
| 1081 | + $fname = 'Parser::doAllQuotes'; |
| 1082 | + wfProfileIn( $fname ); |
1076 | 1083 | $outtext = ''; |
1077 | | - $lines = StringUtils::explode( "\n", $text ); |
| 1084 | + $lines = explode( "\n", $text ); |
1078 | 1085 | foreach ( $lines as $line ) { |
1079 | | - $outtext .= $this->doQuotes( $line ) . "\n"; |
| 1086 | + $outtext .= $this->doQuotes ( $line ) . "\n"; |
1080 | 1087 | } |
1081 | 1088 | $outtext = substr($outtext, 0,-1); |
1082 | | - wfProfileOut( __METHOD__ ); |
| 1089 | + wfProfileOut( $fname ); |
1083 | 1090 | return $outtext; |
1084 | 1091 | } |
1085 | 1092 | |
— | — | @@ -1257,7 +1264,8 @@ |
1258 | 1265 | */ |
1259 | 1266 | function replaceExternalLinks( $text ) { |
1260 | 1267 | global $wgContLang; |
1261 | | - wfProfileIn( __METHOD__ ); |
| 1268 | + $fname = 'Parser::replaceExternalLinks'; |
| 1269 | + wfProfileIn( $fname ); |
1262 | 1270 | |
1263 | 1271 | $sk = $this->mOptions->getSkin(); |
1264 | 1272 | |
— | — | @@ -1327,11 +1335,11 @@ |
1328 | 1336 | # Register link in the output object. |
1329 | 1337 | # Replace unnecessary URL escape codes with the referenced character |
1330 | 1338 | # This prevents spammers from hiding links from the filters |
1331 | | - $pasteurized = self::replaceUnusualEscapes( $url ); |
| 1339 | + $pasteurized = Parser::replaceUnusualEscapes( $url ); |
1332 | 1340 | $this->mOutput->addExternalLink( $pasteurized ); |
1333 | 1341 | } |
1334 | 1342 | |
1335 | | - wfProfileOut( __METHOD__ ); |
| 1343 | + wfProfileOut( $fname ); |
1336 | 1344 | return $s; |
1337 | 1345 | } |
1338 | 1346 | |
— | — | @@ -1341,7 +1349,8 @@ |
1342 | 1350 | */ |
1343 | 1351 | function replaceFreeExternalLinks( $text ) { |
1344 | 1352 | global $wgContLang; |
1345 | | - wfProfileIn( __METHOD__ ); |
| 1353 | + $fname = 'Parser::replaceFreeExternalLinks'; |
| 1354 | + wfProfileIn( $fname ); |
1346 | 1355 | |
1347 | 1356 | $bits = preg_split( '/(\b(?:' . wfUrlProtocols() . '))/S', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); |
1348 | 1357 | $s = array_shift( $bits ); |
— | — | @@ -1403,7 +1412,7 @@ |
1404 | 1413 | $text = $sk->makeExternalLink( $url, $wgContLang->markNoConversion($url), true, 'free', $this->mTitle->getNamespace() ); |
1405 | 1414 | # Register it in the output object... |
1406 | 1415 | # Replace unnecessary URL escape codes with their equivalent characters |
1407 | | - $pasteurized = self::replaceUnusualEscapes( $url ); |
| 1416 | + $pasteurized = Parser::replaceUnusualEscapes( $url ); |
1408 | 1417 | $this->mOutput->addExternalLink( $pasteurized ); |
1409 | 1418 | } |
1410 | 1419 | $s .= $text . $trail; |
— | — | @@ -1411,7 +1420,7 @@ |
1412 | 1421 | $s .= $protocol . $remainder; |
1413 | 1422 | } |
1414 | 1423 | } |
1415 | | - wfProfileOut( __METHOD__ ); |
| 1424 | + wfProfileOut( $fname ); |
1416 | 1425 | return $s; |
1417 | 1426 | } |
1418 | 1427 | |
— | — | @@ -1427,7 +1436,7 @@ |
1428 | 1437 | */ |
1429 | 1438 | static function replaceUnusualEscapes( $url ) { |
1430 | 1439 | return preg_replace_callback( '/%[0-9A-Fa-f]{2}/', |
1431 | | - array( __CLASS__, 'replaceUnusualEscapesCallback' ), $url ); |
| 1440 | + array( 'Parser', 'replaceUnusualEscapesCallback' ), $url ); |
1432 | 1441 | } |
1433 | 1442 | |
1434 | 1443 | /** |
— | — | @@ -1471,48 +1480,35 @@ |
1472 | 1481 | |
1473 | 1482 | /** |
1474 | 1483 | * Process [[ ]] wikilinks |
1475 | | - * @return processed text |
1476 | 1484 | * |
1477 | 1485 | * @private |
1478 | 1486 | */ |
1479 | 1487 | function replaceInternalLinks( $s ) { |
1480 | | - $this->mLinkHolders->merge( $this->replaceInternalLinks2( $s ) ); |
1481 | | - return $s; |
1482 | | - } |
1483 | | - |
1484 | | - /** |
1485 | | - * Process [[ ]] wikilinks |
1486 | | - * @return LinkHolderArray |
1487 | | - * |
1488 | | - * @private |
1489 | | - */ |
1490 | | - function replaceInternalLinks2( &$s ) { |
1491 | 1488 | global $wgContLang; |
| 1489 | + static $fname = 'Parser::replaceInternalLinks' ; |
1492 | 1490 | |
1493 | | - wfProfileIn( __METHOD__ ); |
| 1491 | + wfProfileIn( $fname ); |
1494 | 1492 | |
1495 | | - wfProfileIn( __METHOD__.'-setup' ); |
1496 | | - static $tc = FALSE, $e1, $e1_img; |
| 1493 | + wfProfileIn( $fname.'-setup' ); |
| 1494 | + static $tc = FALSE; |
1497 | 1495 | # the % is needed to support urlencoded titles as well |
1498 | | - if ( !$tc ) { |
1499 | | - $tc = Title::legalChars() . '#%'; |
1500 | | - # Match a link having the form [[namespace:link|alternate]]trail |
1501 | | - $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; |
1502 | | - # Match cases where there is no "]]", which might still be images |
1503 | | - $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; |
1504 | | - } |
| 1496 | + if ( !$tc ) { $tc = Title::legalChars() . '#%'; } |
1505 | 1497 | |
1506 | 1498 | $sk = $this->mOptions->getSkin(); |
1507 | | - $holders = new LinkHolderArray( $this ); |
1508 | 1499 | |
1509 | 1500 | #split the entire text string on occurences of [[ |
1510 | | - $a = StringUtils::explode( '[[', ' ' . $s ); |
| 1501 | + $a = explode( '[[', ' ' . $s ); |
1511 | 1502 | #get the first element (all text up to first [[), and remove the space we added |
1512 | | - $s = $a->current(); |
1513 | | - $a->next(); |
1514 | | - $line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void" |
| 1503 | + $s = array_shift( $a ); |
1515 | 1504 | $s = substr( $s, 1 ); |
1516 | 1505 | |
| 1506 | + # Match a link having the form [[namespace:link|alternate]]trail |
| 1507 | + static $e1 = FALSE; |
| 1508 | + if ( !$e1 ) { $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; } |
| 1509 | + # Match cases where there is no "]]", which might still be images |
| 1510 | + static $e1_img = FALSE; |
| 1511 | + if ( !$e1_img ) { $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } |
| 1512 | + |
1517 | 1513 | $useLinkPrefixExtension = $wgContLang->linkPrefixExtension(); |
1518 | 1514 | $e2 = null; |
1519 | 1515 | if ( $useLinkPrefixExtension ) { |
— | — | @@ -1522,8 +1518,8 @@ |
1523 | 1519 | } |
1524 | 1520 | |
1525 | 1521 | if( is_null( $this->mTitle ) ) { |
1526 | | - wfProfileOut( __METHOD__ ); |
1527 | | - wfProfileOut( __METHOD__.'-setup' ); |
| 1522 | + wfProfileOut( $fname ); |
| 1523 | + wfProfileOut( $fname.'-setup' ); |
1528 | 1524 | throw new MWException( __METHOD__.": \$this->mTitle is null\n" ); |
1529 | 1525 | } |
1530 | 1526 | $nottalk = !$this->mTitle->isTalkPage(); |
— | — | @@ -1545,20 +1541,13 @@ |
1546 | 1542 | $selflink = array($this->mTitle->getPrefixedText()); |
1547 | 1543 | } |
1548 | 1544 | $useSubpages = $this->areSubpagesAllowed(); |
1549 | | - wfProfileOut( __METHOD__.'-setup' ); |
| 1545 | + wfProfileOut( $fname.'-setup' ); |
1550 | 1546 | |
1551 | 1547 | # Loop for each link |
1552 | | - for ( ; $line !== false && $line !== null ; $a->next(), $line = $a->current() ) { |
1553 | | - # Check for excessive memory usage |
1554 | | - if ( $holders->isBig() ) { |
1555 | | - # Too big |
1556 | | - # Do the existence check, replace the link holders and clear the array |
1557 | | - $holders->replace( $s ); |
1558 | | - $holders->clear(); |
1559 | | - } |
1560 | | - |
| 1548 | + for ($k = 0; isset( $a[$k] ); $k++) { |
| 1549 | + $line = $a[$k]; |
1561 | 1550 | if ( $useLinkPrefixExtension ) { |
1562 | | - wfProfileIn( __METHOD__.'-prefixhandling' ); |
| 1551 | + wfProfileIn( $fname.'-prefixhandling' ); |
1563 | 1552 | if ( preg_match( $e2, $s, $m ) ) { |
1564 | 1553 | $prefix = $m[2]; |
1565 | 1554 | $s = $m[1]; |
— | — | @@ -1570,12 +1559,12 @@ |
1571 | 1560 | $prefix = $first_prefix; |
1572 | 1561 | $first_prefix = false; |
1573 | 1562 | } |
1574 | | - wfProfileOut( __METHOD__.'-prefixhandling' ); |
| 1563 | + wfProfileOut( $fname.'-prefixhandling' ); |
1575 | 1564 | } |
1576 | 1565 | |
1577 | 1566 | $might_be_img = false; |
1578 | 1567 | |
1579 | | - wfProfileIn( __METHOD__."-e1" ); |
| 1568 | + wfProfileIn( "$fname-e1" ); |
1580 | 1569 | if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt |
1581 | 1570 | $text = $m[2]; |
1582 | 1571 | # If we get a ] at the beginning of $m[3] that means we have a link that's something like: |
— | — | @@ -1609,18 +1598,18 @@ |
1610 | 1599 | $trail = ""; |
1611 | 1600 | } else { # Invalid form; output directly |
1612 | 1601 | $s .= $prefix . '[[' . $line ; |
1613 | | - wfProfileOut( __METHOD__."-e1" ); |
| 1602 | + wfProfileOut( "$fname-e1" ); |
1614 | 1603 | continue; |
1615 | 1604 | } |
1616 | | - wfProfileOut( __METHOD__."-e1" ); |
1617 | | - wfProfileIn( __METHOD__."-misc" ); |
| 1605 | + wfProfileOut( "$fname-e1" ); |
| 1606 | + wfProfileIn( "$fname-misc" ); |
1618 | 1607 | |
1619 | 1608 | # Don't allow internal links to pages containing |
1620 | 1609 | # PROTO: where PROTO is a valid URL protocol; these |
1621 | 1610 | # should be external links. |
1622 | 1611 | if (preg_match('/^\b(?:' . wfUrlProtocols() . ')/', $m[1])) { |
1623 | 1612 | $s .= $prefix . '[[' . $line ; |
1624 | | - wfProfileOut( __METHOD__."-misc" ); |
| 1613 | + wfProfileOut( "$fname-misc" ); |
1625 | 1614 | continue; |
1626 | 1615 | } |
1627 | 1616 | |
— | — | @@ -1637,30 +1626,27 @@ |
1638 | 1627 | $link = substr($link, 1); |
1639 | 1628 | } |
1640 | 1629 | |
1641 | | - wfProfileOut( __METHOD__."-misc" ); |
1642 | | - wfProfileIn( __METHOD__."-title" ); |
| 1630 | + wfProfileOut( "$fname-misc" ); |
| 1631 | + wfProfileIn( "$fname-title" ); |
1643 | 1632 | $nt = Title::newFromText( $this->mStripState->unstripNoWiki($link) ); |
1644 | 1633 | if( !$nt ) { |
1645 | 1634 | $s .= $prefix . '[[' . $line; |
1646 | | - wfProfileOut( __METHOD__."-title" ); |
| 1635 | + wfProfileOut( "$fname-title" ); |
1647 | 1636 | continue; |
1648 | 1637 | } |
1649 | 1638 | |
1650 | 1639 | $ns = $nt->getNamespace(); |
1651 | 1640 | $iw = $nt->getInterWiki(); |
1652 | | - wfProfileOut( __METHOD__."-title" ); |
| 1641 | + wfProfileOut( "$fname-title" ); |
1653 | 1642 | |
1654 | 1643 | if ($might_be_img) { # if this is actually an invalid link |
1655 | | - wfProfileIn( __METHOD__."-might_be_img" ); |
| 1644 | + wfProfileIn( "$fname-might_be_img" ); |
1656 | 1645 | if ($ns == NS_IMAGE && $noforce) { #but might be an image |
1657 | 1646 | $found = false; |
1658 | | - while ( true ) { |
| 1647 | + while (isset ($a[$k+1]) ) { |
1659 | 1648 | #look at the next 'line' to see if we can close it there |
1660 | | - $a->next(); |
1661 | | - $next_line = $a->current(); |
1662 | | - if ( $next_line === false || $next_line === null ) { |
1663 | | - break; |
1664 | | - } |
| 1649 | + $spliced = array_splice( $a, $k + 1, 1 ); |
| 1650 | + $next_line = array_shift( $spliced ); |
1665 | 1651 | $m = explode( ']]', $next_line, 3 ); |
1666 | 1652 | if ( count( $m ) == 3 ) { |
1667 | 1653 | # the first ]] closes the inner link, the second the image |
— | — | @@ -1680,19 +1666,19 @@ |
1681 | 1667 | if ( !$found ) { |
1682 | 1668 | # we couldn't find the end of this imageLink, so output it raw |
1683 | 1669 | #but don't ignore what might be perfectly normal links in the text we've examined |
1684 | | - $holders->merge( $this->replaceInternalLinks2( $text ) ); |
| 1670 | + $text = $this->replaceInternalLinks($text); |
1685 | 1671 | $s .= "{$prefix}[[$link|$text"; |
1686 | 1672 | # note: no $trail, because without an end, there *is* no trail |
1687 | | - wfProfileOut( __METHOD__."-might_be_img" ); |
| 1673 | + wfProfileOut( "$fname-might_be_img" ); |
1688 | 1674 | continue; |
1689 | 1675 | } |
1690 | 1676 | } else { #it's not an image, so output it raw |
1691 | 1677 | $s .= "{$prefix}[[$link|$text"; |
1692 | 1678 | # note: no $trail, because without an end, there *is* no trail |
1693 | | - wfProfileOut( __METHOD__."-might_be_img" ); |
| 1679 | + wfProfileOut( "$fname-might_be_img" ); |
1694 | 1680 | continue; |
1695 | 1681 | } |
1696 | | - wfProfileOut( __METHOD__."-might_be_img" ); |
| 1682 | + wfProfileOut( "$fname-might_be_img" ); |
1697 | 1683 | } |
1698 | 1684 | |
1699 | 1685 | $wasblank = ( '' == $text ); |
— | — | @@ -1702,38 +1688,41 @@ |
1703 | 1689 | if( $noforce ) { |
1704 | 1690 | |
1705 | 1691 | # Interwikis |
1706 | | - wfProfileIn( __METHOD__."-interwiki" ); |
| 1692 | + wfProfileIn( "$fname-interwiki" ); |
1707 | 1693 | if( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && $wgContLang->getLanguageName( $iw ) ) { |
1708 | 1694 | $this->mOutput->addLanguageLink( $nt->getFullText() ); |
1709 | 1695 | $s = rtrim($s . $prefix); |
1710 | 1696 | $s .= trim($trail, "\n") == '' ? '': $prefix . $trail; |
1711 | | - wfProfileOut( __METHOD__."-interwiki" ); |
| 1697 | + wfProfileOut( "$fname-interwiki" ); |
1712 | 1698 | continue; |
1713 | 1699 | } |
1714 | | - wfProfileOut( __METHOD__."-interwiki" ); |
| 1700 | + wfProfileOut( "$fname-interwiki" ); |
1715 | 1701 | |
1716 | 1702 | if ( $ns == NS_IMAGE ) { |
1717 | | - wfProfileIn( __METHOD__."-image" ); |
| 1703 | + wfProfileIn( "$fname-image" ); |
1718 | 1704 | if ( !wfIsBadImage( $nt->getDBkey(), $this->mTitle ) ) { |
1719 | 1705 | # recursively parse links inside the image caption |
1720 | 1706 | # actually, this will parse them in any other parameters, too, |
1721 | 1707 | # but it might be hard to fix that, and it doesn't matter ATM |
1722 | 1708 | $text = $this->replaceExternalLinks($text); |
1723 | | - $holders->merge( $this->replaceInternalLinks2( $text ) ); |
| 1709 | + $text = $this->replaceInternalLinks($text); |
1724 | 1710 | |
1725 | 1711 | # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them |
1726 | | - $s .= $prefix . $this->armorLinks( $this->makeImage( $nt, $text, $holders ) ) . $trail; |
| 1712 | + $s .= $prefix . $this->armorLinks( $this->makeImage( $nt, $text ) ) . $trail; |
| 1713 | + $this->mOutput->addImage( $nt->getDBkey() ); |
1727 | 1714 | |
1728 | | - wfProfileOut( __METHOD__."-image" ); |
| 1715 | + wfProfileOut( "$fname-image" ); |
1729 | 1716 | continue; |
| 1717 | + } else { |
| 1718 | + # We still need to record the image's presence on the page |
| 1719 | + $this->mOutput->addImage( $nt->getDBkey() ); |
1730 | 1720 | } |
1731 | | - $this->mOutput->addImage( $nt->getDBkey() ); |
1732 | | - wfProfileOut( __METHOD__."-image" ); |
| 1721 | + wfProfileOut( "$fname-image" ); |
1733 | 1722 | |
1734 | 1723 | } |
1735 | 1724 | |
1736 | 1725 | if ( $ns == NS_CATEGORY ) { |
1737 | | - wfProfileIn( __METHOD__."-category" ); |
| 1726 | + wfProfileIn( "$fname-category" ); |
1738 | 1727 | $s = rtrim($s . "\n"); # bug 87 |
1739 | 1728 | |
1740 | 1729 | if ( $wasblank ) { |
— | — | @@ -1752,7 +1741,7 @@ |
1753 | 1742 | */ |
1754 | 1743 | $s .= trim($prefix . $trail, "\n") == '' ? '': $prefix . $trail; |
1755 | 1744 | |
1756 | | - wfProfileOut( __METHOD__."-category" ); |
| 1745 | + wfProfileOut( "$fname-category" ); |
1757 | 1746 | continue; |
1758 | 1747 | } |
1759 | 1748 | } |
— | — | @@ -1783,7 +1772,7 @@ |
1784 | 1773 | if( SpecialPage::exists( $nt->getDBkey() ) ) { |
1785 | 1774 | $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix ); |
1786 | 1775 | } else { |
1787 | | - $s .= $holders->makeHolder( $nt, $text, '', $trail, $prefix ); |
| 1776 | + $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix ); |
1788 | 1777 | } |
1789 | 1778 | continue; |
1790 | 1779 | } elseif( $ns == NS_IMAGE ) { |
— | — | @@ -1797,10 +1786,10 @@ |
1798 | 1787 | continue; |
1799 | 1788 | } |
1800 | 1789 | } |
1801 | | - $s .= $holders->makeHolder( $nt, $text, '', $trail, $prefix ); |
| 1790 | + $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix ); |
1802 | 1791 | } |
1803 | | - wfProfileOut( __METHOD__ ); |
1804 | | - return $holders; |
| 1792 | + wfProfileOut( $fname ); |
| 1793 | + return $s; |
1805 | 1794 | } |
1806 | 1795 | |
1807 | 1796 | /** |
— | — | @@ -1809,10 +1798,32 @@ |
1810 | 1799 | * parsing of interwiki links, and secondly to allow all existence checks and |
1811 | 1800 | * article length checks (for stub links) to be bundled into a single query. |
1812 | 1801 | * |
1813 | | - * @deprecated |
1814 | 1802 | */ |
1815 | 1803 | function makeLinkHolder( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) { |
1816 | | - return $this->mLinkHolders->makeHolder( $nt, $text, $query, $trail, $prefix ); |
| 1804 | + wfProfileIn( __METHOD__ ); |
| 1805 | + if ( ! is_object($nt) ) { |
| 1806 | + # Fail gracefully |
| 1807 | + $retVal = "<!-- ERROR -->{$prefix}{$text}{$trail}"; |
| 1808 | + } else { |
| 1809 | + # Separate the link trail from the rest of the link |
| 1810 | + list( $inside, $trail ) = Linker::splitTrail( $trail ); |
| 1811 | + |
| 1812 | + if ( $nt->isExternal() ) { |
| 1813 | + $nr = array_push( $this->mInterwikiLinkHolders['texts'], $prefix.$text.$inside ); |
| 1814 | + $this->mInterwikiLinkHolders['titles'][] = $nt; |
| 1815 | + $retVal = '<!--IWLINK '. ($nr-1) ."-->{$trail}"; |
| 1816 | + } else { |
| 1817 | + $nr = array_push( $this->mLinkHolders['namespaces'], $nt->getNamespace() ); |
| 1818 | + $this->mLinkHolders['dbkeys'][] = $nt->getDBkey(); |
| 1819 | + $this->mLinkHolders['queries'][] = $query; |
| 1820 | + $this->mLinkHolders['texts'][] = $prefix.$text.$inside; |
| 1821 | + $this->mLinkHolders['titles'][] = $nt; |
| 1822 | + |
| 1823 | + $retVal = '<!--LINK '. ($nr-1) ."-->{$trail}"; |
| 1824 | + } |
| 1825 | + } |
| 1826 | + wfProfileOut( __METHOD__ ); |
| 1827 | + return $retVal; |
1817 | 1828 | } |
1818 | 1829 | |
1819 | 1830 | /** |
— | — | @@ -1878,7 +1889,8 @@ |
1879 | 1890 | # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage |
1880 | 1891 | # ../Foobar -- convert to CurrentPage/Foobar, from CurrentPage/CurrentSubPage |
1881 | 1892 | |
1882 | | - wfProfileIn( __METHOD__ ); |
| 1893 | + $fname = 'Parser::maybeDoSubpageLink'; |
| 1894 | + wfProfileIn( $fname ); |
1883 | 1895 | $ret = $target; # default return value is no change |
1884 | 1896 | |
1885 | 1897 | # Some namespaces don't allow subpages, |
— | — | @@ -1937,7 +1949,7 @@ |
1938 | 1950 | } |
1939 | 1951 | } |
1940 | 1952 | |
1941 | | - wfProfileOut( __METHOD__ ); |
| 1953 | + wfProfileOut( $fname ); |
1942 | 1954 | return $ret; |
1943 | 1955 | } |
1944 | 1956 | |
— | — | @@ -2024,53 +2036,50 @@ |
2025 | 2037 | * @return string the lists rendered as HTML |
2026 | 2038 | */ |
2027 | 2039 | function doBlockLevels( $text, $linestart ) { |
2028 | | - wfProfileIn( __METHOD__ ); |
| 2040 | + $fname = 'Parser::doBlockLevels'; |
| 2041 | + wfProfileIn( $fname ); |
2029 | 2042 | |
2030 | 2043 | # Parsing through the text line by line. The main thing |
2031 | 2044 | # happening here is handling of block-level elements p, pre, |
2032 | 2045 | # and making lists from lines starting with * # : etc. |
2033 | 2046 | # |
2034 | | - $textLines = StringUtils::explode( "\n", $text ); |
| 2047 | + $textLines = explode( "\n", $text ); |
2035 | 2048 | |
2036 | 2049 | $lastPrefix = $output = ''; |
2037 | 2050 | $this->mDTopen = $inBlockElem = false; |
2038 | 2051 | $prefixLength = 0; |
2039 | 2052 | $paragraphStack = false; |
2040 | 2053 | |
| 2054 | + if ( !$linestart ) { |
| 2055 | + $output .= array_shift( $textLines ); |
| 2056 | + } |
2041 | 2057 | foreach ( $textLines as $oLine ) { |
2042 | | - # Fix up $linestart |
2043 | | - if ( !$linestart ) { |
2044 | | - $output .= $oLine; |
2045 | | - $linestart = true; |
2046 | | - continue; |
2047 | | - } |
2048 | | - |
2049 | 2058 | $lastPrefixLength = strlen( $lastPrefix ); |
2050 | 2059 | $preCloseMatch = preg_match('/<\\/pre/i', $oLine ); |
2051 | 2060 | $preOpenMatch = preg_match('/<pre/i', $oLine ); |
2052 | 2061 | if ( !$this->mInPre ) { |
2053 | 2062 | # Multiple prefixes may abut each other for nested lists. |
2054 | 2063 | $prefixLength = strspn( $oLine, '*#:;' ); |
2055 | | - $prefix = substr( $oLine, 0, $prefixLength ); |
| 2064 | + $pref = substr( $oLine, 0, $prefixLength ); |
2056 | 2065 | |
2057 | 2066 | # eh? |
2058 | | - $prefix2 = str_replace( ';', ':', $prefix ); |
| 2067 | + $pref2 = str_replace( ';', ':', $pref ); |
2059 | 2068 | $t = substr( $oLine, $prefixLength ); |
2060 | | - $this->mInPre = (bool)$preOpenMatch; |
| 2069 | + $this->mInPre = !empty($preOpenMatch); |
2061 | 2070 | } else { |
2062 | 2071 | # Don't interpret any other prefixes in preformatted text |
2063 | 2072 | $prefixLength = 0; |
2064 | | - $prefix = $prefix2 = ''; |
| 2073 | + $pref = $pref2 = ''; |
2065 | 2074 | $t = $oLine; |
2066 | 2075 | } |
2067 | 2076 | |
2068 | 2077 | # List generation |
2069 | | - if( $prefixLength && $lastPrefix === $prefix2 ) { |
| 2078 | + if( $prefixLength && 0 == strcmp( $lastPrefix, $pref2 ) ) { |
2070 | 2079 | # Same as the last item, so no need to deal with nesting or opening stuff |
2071 | | - $output .= $this->nextItem( substr( $prefix, -1 ) ); |
| 2080 | + $output .= $this->nextItem( substr( $pref, -1 ) ); |
2072 | 2081 | $paragraphStack = false; |
2073 | 2082 | |
2074 | | - if ( substr( $prefix, -1 ) == ';') { |
| 2083 | + if ( substr( $pref, -1 ) == ';') { |
2075 | 2084 | # The one nasty exception: definition lists work like this: |
2076 | 2085 | # ; title : definition text |
2077 | 2086 | # So we check for : in the remainder text to split up the |
— | — | @@ -2083,18 +2092,18 @@ |
2084 | 2093 | } |
2085 | 2094 | } elseif( $prefixLength || $lastPrefixLength ) { |
2086 | 2095 | # Either open or close a level... |
2087 | | - $commonPrefixLength = $this->getCommon( $prefix, $lastPrefix ); |
| 2096 | + $commonPrefixLength = $this->getCommon( $pref, $lastPrefix ); |
2088 | 2097 | $paragraphStack = false; |
2089 | 2098 | |
2090 | 2099 | while( $commonPrefixLength < $lastPrefixLength ) { |
2091 | | - $output .= $this->closeList( $lastPrefix[$lastPrefixLength-1] ); |
| 2100 | + $output .= $this->closeList( $lastPrefix{$lastPrefixLength-1} ); |
2092 | 2101 | --$lastPrefixLength; |
2093 | 2102 | } |
2094 | 2103 | if ( $prefixLength <= $commonPrefixLength && $commonPrefixLength > 0 ) { |
2095 | | - $output .= $this->nextItem( $prefix[$commonPrefixLength-1] ); |
| 2104 | + $output .= $this->nextItem( $pref{$commonPrefixLength-1} ); |
2096 | 2105 | } |
2097 | 2106 | while ( $prefixLength > $commonPrefixLength ) { |
2098 | | - $char = substr( $prefix, $commonPrefixLength, 1 ); |
| 2107 | + $char = substr( $pref, $commonPrefixLength, 1 ); |
2099 | 2108 | $output .= $this->openList( $char ); |
2100 | 2109 | |
2101 | 2110 | if ( ';' == $char ) { |
— | — | @@ -2106,10 +2115,10 @@ |
2107 | 2116 | } |
2108 | 2117 | ++$commonPrefixLength; |
2109 | 2118 | } |
2110 | | - $lastPrefix = $prefix2; |
| 2119 | + $lastPrefix = $pref2; |
2111 | 2120 | } |
2112 | 2121 | if( 0 == $prefixLength ) { |
2113 | | - wfProfileIn( __METHOD__."-paragraph" ); |
| 2122 | + wfProfileIn( "$fname-paragraph" ); |
2114 | 2123 | # No prefix (not in list)--go to paragraph mode |
2115 | 2124 | // XXX: use a stack for nestable elements like span, table and div |
2116 | 2125 | $openmatch = preg_match('/(?:<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS', $t ); |
— | — | @@ -2165,7 +2174,7 @@ |
2166 | 2175 | } |
2167 | 2176 | } |
2168 | 2177 | } |
2169 | | - wfProfileOut( __METHOD__."-paragraph" ); |
| 2178 | + wfProfileOut( "$fname-paragraph" ); |
2170 | 2179 | } |
2171 | 2180 | // somewhere above we forget to get out of pre block (bug 785) |
2172 | 2181 | if($preCloseMatch && $this->mInPre) { |
— | — | @@ -2176,7 +2185,7 @@ |
2177 | 2186 | } |
2178 | 2187 | } |
2179 | 2188 | while ( $prefixLength ) { |
2180 | | - $output .= $this->closeList( $prefix2[$prefixLength-1] ); |
| 2189 | + $output .= $this->closeList( $pref2{$prefixLength-1} ); |
2181 | 2190 | --$prefixLength; |
2182 | 2191 | } |
2183 | 2192 | if ( '' != $this->mLastSection ) { |
— | — | @@ -2184,7 +2193,7 @@ |
2185 | 2194 | $this->mLastSection = ''; |
2186 | 2195 | } |
2187 | 2196 | |
2188 | | - wfProfileOut( __METHOD__ ); |
| 2197 | + wfProfileOut( $fname ); |
2189 | 2198 | return $output; |
2190 | 2199 | } |
2191 | 2200 | |
— | — | @@ -2197,12 +2206,13 @@ |
2198 | 2207 | * return string the position of the ':', or false if none found |
2199 | 2208 | */ |
2200 | 2209 | function findColonNoLinks($str, &$before, &$after) { |
2201 | | - wfProfileIn( __METHOD__ ); |
| 2210 | + $fname = 'Parser::findColonNoLinks'; |
| 2211 | + wfProfileIn( $fname ); |
2202 | 2212 | |
2203 | 2213 | $pos = strpos( $str, ':' ); |
2204 | 2214 | if( $pos === false ) { |
2205 | 2215 | // Nothing to find! |
2206 | | - wfProfileOut( __METHOD__ ); |
| 2216 | + wfProfileOut( $fname ); |
2207 | 2217 | return false; |
2208 | 2218 | } |
2209 | 2219 | |
— | — | @@ -2211,7 +2221,7 @@ |
2212 | 2222 | // Easy; no tag nesting to worry about |
2213 | 2223 | $before = substr( $str, 0, $pos ); |
2214 | 2224 | $after = substr( $str, $pos+1 ); |
2215 | | - wfProfileOut( __METHOD__ ); |
| 2225 | + wfProfileOut( $fname ); |
2216 | 2226 | return $pos; |
2217 | 2227 | } |
2218 | 2228 | |
— | — | @@ -2235,7 +2245,7 @@ |
2236 | 2246 | // We found it! |
2237 | 2247 | $before = substr( $str, 0, $i ); |
2238 | 2248 | $after = substr( $str, $i + 1 ); |
2239 | | - wfProfileOut( __METHOD__ ); |
| 2249 | + wfProfileOut( $fname ); |
2240 | 2250 | return $i; |
2241 | 2251 | } |
2242 | 2252 | // Embedded in a tag; don't break it. |
— | — | @@ -2245,7 +2255,7 @@ |
2246 | 2256 | $colon = strpos( $str, ':', $i ); |
2247 | 2257 | if( $colon === false ) { |
2248 | 2258 | // Nothing else interesting |
2249 | | - wfProfileOut( __METHOD__ ); |
| 2259 | + wfProfileOut( $fname ); |
2250 | 2260 | return false; |
2251 | 2261 | } |
2252 | 2262 | $lt = strpos( $str, '<', $i ); |
— | — | @@ -2254,7 +2264,7 @@ |
2255 | 2265 | // We found it! |
2256 | 2266 | $before = substr( $str, 0, $colon ); |
2257 | 2267 | $after = substr( $str, $colon + 1 ); |
2258 | | - wfProfileOut( __METHOD__ ); |
| 2268 | + wfProfileOut( $fname ); |
2259 | 2269 | return $i; |
2260 | 2270 | } |
2261 | 2271 | } |
— | — | @@ -2304,8 +2314,8 @@ |
2305 | 2315 | if( $c == ">" ) { |
2306 | 2316 | $stack--; |
2307 | 2317 | if( $stack < 0 ) { |
2308 | | - wfDebug( __METHOD__.": Invalid input; too many close tags\n" ); |
2309 | | - wfProfileOut( __METHOD__ ); |
| 2318 | + wfDebug( "Invalid input in $fname; too many close tags\n" ); |
| 2319 | + wfProfileOut( $fname ); |
2310 | 2320 | return false; |
2311 | 2321 | } |
2312 | 2322 | $state = self::COLON_STATE_TEXT; |
— | — | @@ -2340,14 +2350,14 @@ |
2341 | 2351 | } |
2342 | 2352 | break; |
2343 | 2353 | default: |
2344 | | - throw new MWException( "State machine error in " . __METHOD__ ); |
| 2354 | + throw new MWException( "State machine error in $fname" ); |
2345 | 2355 | } |
2346 | 2356 | } |
2347 | 2357 | if( $stack > 0 ) { |
2348 | | - wfDebug( __METHOD__.": Invalid input; not enough close tags (stack $stack, state $state)\n" ); |
| 2358 | + wfDebug( "Invalid input in $fname; not enough close tags (stack $stack, state $state)\n" ); |
2349 | 2359 | return false; |
2350 | 2360 | } |
2351 | | - wfProfileOut( __METHOD__ ); |
| 2361 | + wfProfileOut( $fname ); |
2352 | 2362 | return false; |
2353 | 2363 | } |
2354 | 2364 | |
— | — | @@ -2577,11 +2587,12 @@ |
2578 | 2588 | * @private |
2579 | 2589 | */ |
2580 | 2590 | function initialiseVariables() { |
2581 | | - wfProfileIn( __METHOD__ ); |
| 2591 | + $fname = 'Parser::initialiseVariables'; |
| 2592 | + wfProfileIn( $fname ); |
2582 | 2593 | $variableIDs = MagicWord::getVariableIDs(); |
2583 | 2594 | |
2584 | 2595 | $this->mVariables = new MagicWordArray( $variableIDs ); |
2585 | | - wfProfileOut( __METHOD__ ); |
| 2596 | + wfProfileOut( $fname ); |
2586 | 2597 | } |
2587 | 2598 | |
2588 | 2599 | /** |
— | — | @@ -2650,7 +2661,8 @@ |
2651 | 2662 | return $text; |
2652 | 2663 | } |
2653 | 2664 | |
2654 | | - wfProfileIn( __METHOD__ ); |
| 2665 | + $fname = __METHOD__; |
| 2666 | + wfProfileIn( $fname ); |
2655 | 2667 | |
2656 | 2668 | if ( $frame === false ) { |
2657 | 2669 | $frame = $this->getPreprocessor()->newFrame(); |
— | — | @@ -2663,7 +2675,7 @@ |
2664 | 2676 | $flags = $argsOnly ? PPFrame::NO_TEMPLATES : 0; |
2665 | 2677 | $text = $frame->expand( $dom, $flags ); |
2666 | 2678 | |
2667 | | - wfProfileOut( __METHOD__ ); |
| 2679 | + wfProfileOut( $fname ); |
2668 | 2680 | return $text; |
2669 | 2681 | } |
2670 | 2682 | |
— | — | @@ -2726,7 +2738,8 @@ |
2727 | 2739 | */ |
2728 | 2740 | function braceSubstitution( $piece, $frame ) { |
2729 | 2741 | global $wgContLang, $wgLang, $wgAllowDisplayTitle, $wgNonincludableNamespaces; |
2730 | | - wfProfileIn( __METHOD__ ); |
| 2742 | + $fname = __METHOD__; |
| 2743 | + wfProfileIn( $fname ); |
2731 | 2744 | wfProfileIn( __METHOD__.'-setup' ); |
2732 | 2745 | |
2733 | 2746 | # Flags |
— | — | @@ -2913,7 +2926,7 @@ |
2914 | 2927 | } |
2915 | 2928 | } else if ( $wgNonincludableNamespaces && in_array( $title->getNamespace(), $wgNonincludableNamespaces ) ) { |
2916 | 2929 | $found = false; //access denied |
2917 | | - wfDebug( __METHOD__.": template inclusion denied for " . $title->getPrefixedDBkey() ); |
| 2930 | + wfDebug( "$fname: template inclusion denied for " . $title->getPrefixedDBkey() ); |
2918 | 2931 | } else { |
2919 | 2932 | list( $text, $title ) = $this->getTemplateDom( $title ); |
2920 | 2933 | if ( $text !== false ) { |
— | — | @@ -2947,7 +2960,7 @@ |
2948 | 2961 | # Recover the source wikitext and return it |
2949 | 2962 | if ( !$found ) { |
2950 | 2963 | $text = $frame->virtualBracketedImplode( '{{', '|', '}}', $titleWithSpaces, $args ); |
2951 | | - wfProfileOut( __METHOD__ ); |
| 2964 | + wfProfileOut( $fname ); |
2952 | 2965 | return array( 'object' => $text ); |
2953 | 2966 | } |
2954 | 2967 | |
— | — | @@ -3006,7 +3019,7 @@ |
3007 | 3020 | $ret = array( 'text' => $text ); |
3008 | 3021 | } |
3009 | 3022 | |
3010 | | - wfProfileOut( __METHOD__ ); |
| 3023 | + wfProfileOut( $fname ); |
3011 | 3024 | return $ret; |
3012 | 3025 | } |
3013 | 3026 | |
— | — | @@ -3549,7 +3562,12 @@ |
3550 | 3563 | # <!--LINK number--> |
3551 | 3564 | # turns into |
3552 | 3565 | # link text with suffix |
3553 | | - $safeHeadline = $this->replaceLinkHoldersText( $safeHeadline ); |
| 3566 | + $safeHeadline = preg_replace( '/<!--LINK ([0-9]*)-->/e', |
| 3567 | + "\$this->mLinkHolders['texts'][\$1]", |
| 3568 | + $safeHeadline ); |
| 3569 | + $safeHeadline = preg_replace( '/<!--IWLINK ([0-9]*)-->/e', |
| 3570 | + "\$this->mInterwikiLinkHolders['texts'][\$1]", |
| 3571 | + $safeHeadline ); |
3554 | 3572 | |
3555 | 3573 | # Strip out HTML (other than plain <sup> and <sub>: bug 8393) |
3556 | 3574 | $tocline = preg_replace( |
— | — | @@ -3777,7 +3795,7 @@ |
3778 | 3796 | } else { |
3779 | 3797 | # Failed to validate; fall back to the default |
3780 | 3798 | $nickname = $username; |
3781 | | - wfDebug( __METHOD__.": $username has bad XML tags in signature.\n" ); |
| 3799 | + wfDebug( "Parser::getUserSig: $username has bad XML tags in signature.\n" ); |
3782 | 3800 | } |
3783 | 3801 | } |
3784 | 3802 | |
— | — | @@ -3883,17 +3901,19 @@ |
3884 | 3902 | global $wgTitle; |
3885 | 3903 | static $executing = false; |
3886 | 3904 | |
| 3905 | + $fname = "Parser::transformMsg"; |
| 3906 | + |
3887 | 3907 | # Guard against infinite recursion |
3888 | 3908 | if ( $executing ) { |
3889 | 3909 | return $text; |
3890 | 3910 | } |
3891 | 3911 | $executing = true; |
3892 | 3912 | |
3893 | | - wfProfileIn(__METHOD__); |
| 3913 | + wfProfileIn($fname); |
3894 | 3914 | $text = $this->preprocess( $text, $wgTitle, $options ); |
3895 | 3915 | |
3896 | 3916 | $executing = false; |
3897 | | - wfProfileOut(__METHOD__); |
| 3917 | + wfProfileOut($fname); |
3898 | 3918 | return $text; |
3899 | 3919 | } |
3900 | 3920 | |
— | — | @@ -3990,7 +4010,7 @@ |
3991 | 4011 | # Add to function cache |
3992 | 4012 | $mw = MagicWord::get( $id ); |
3993 | 4013 | if( !$mw ) |
3994 | | - throw new MWException( __METHOD__.'() expecting a magic word identifier.' ); |
| 4014 | + throw new MWException( 'Parser::setFunctionHook() expecting a magic word identifier.' ); |
3995 | 4015 | |
3996 | 4016 | $synonyms = $mw->getSynonyms(); |
3997 | 4017 | $sensitive = intval( $mw->isCaseSensitive() ); |
— | — | @@ -4026,9 +4046,266 @@ |
4027 | 4047 | * Replace <!--LINK--> link placeholders with actual links, in the buffer |
4028 | 4048 | * Placeholders created in Skin::makeLinkObj() |
4029 | 4049 | * Returns an array of link CSS classes, indexed by PDBK. |
| 4050 | + * $options is a bit field, RLH_FOR_UPDATE to select for update |
4030 | 4051 | */ |
4031 | 4052 | function replaceLinkHolders( &$text, $options = 0 ) { |
4032 | | - return $this->mLinkHolders->replace( $text ); |
| 4053 | + global $wgUser; |
| 4054 | + global $wgContLang; |
| 4055 | + |
| 4056 | + $fname = 'Parser::replaceLinkHolders'; |
| 4057 | + wfProfileIn( $fname ); |
| 4058 | + |
| 4059 | + $pdbks = array(); |
| 4060 | + $colours = array(); |
| 4061 | + $linkcolour_ids = array(); |
| 4062 | + $sk = $this->mOptions->getSkin(); |
| 4063 | + $linkCache = LinkCache::singleton(); |
| 4064 | + |
| 4065 | + if ( !empty( $this->mLinkHolders['namespaces'] ) ) { |
| 4066 | + wfProfileIn( $fname.'-check' ); |
| 4067 | + $dbr = wfGetDB( DB_SLAVE ); |
| 4068 | + $page = $dbr->tableName( 'page' ); |
| 4069 | + $threshold = $wgUser->getOption('stubthreshold'); |
| 4070 | + |
| 4071 | + # Sort by namespace |
| 4072 | + asort( $this->mLinkHolders['namespaces'] ); |
| 4073 | + |
| 4074 | + # Generate query |
| 4075 | + $query = false; |
| 4076 | + $current = null; |
| 4077 | + foreach ( $this->mLinkHolders['namespaces'] as $key => $ns ) { |
| 4078 | + # Make title object |
| 4079 | + $title = $this->mLinkHolders['titles'][$key]; |
| 4080 | + |
| 4081 | + # Skip invalid entries. |
| 4082 | + # Result will be ugly, but prevents crash. |
| 4083 | + if ( is_null( $title ) ) { |
| 4084 | + continue; |
| 4085 | + } |
| 4086 | + $pdbk = $pdbks[$key] = $title->getPrefixedDBkey(); |
| 4087 | + |
| 4088 | + # Check if it's a static known link, e.g. interwiki |
| 4089 | + if ( $title->isAlwaysKnown() ) { |
| 4090 | + $colours[$pdbk] = ''; |
| 4091 | + } elseif ( ( $id = $linkCache->getGoodLinkID( $pdbk ) ) != 0 ) { |
| 4092 | + $colours[$pdbk] = ''; |
| 4093 | + $this->mOutput->addLink( $title, $id ); |
| 4094 | + } elseif ( $linkCache->isBadLink( $pdbk ) ) { |
| 4095 | + $colours[$pdbk] = 'new'; |
| 4096 | + } elseif ( $title->getNamespace() == NS_SPECIAL && !SpecialPage::exists( $pdbk ) ) { |
| 4097 | + $colours[$pdbk] = 'new'; |
| 4098 | + } else { |
| 4099 | + # Not in the link cache, add it to the query |
| 4100 | + if ( !isset( $current ) ) { |
| 4101 | + $current = $ns; |
| 4102 | + $query = "SELECT page_id, page_namespace, page_title, page_is_redirect, page_len"; |
| 4103 | + $query .= " FROM $page WHERE (page_namespace=$ns AND page_title IN("; |
| 4104 | + } elseif ( $current != $ns ) { |
| 4105 | + $current = $ns; |
| 4106 | + $query .= ")) OR (page_namespace=$ns AND page_title IN("; |
| 4107 | + } else { |
| 4108 | + $query .= ', '; |
| 4109 | + } |
| 4110 | + |
| 4111 | + $query .= $dbr->addQuotes( $this->mLinkHolders['dbkeys'][$key] ); |
| 4112 | + } |
| 4113 | + } |
| 4114 | + if ( $query ) { |
| 4115 | + $query .= '))'; |
| 4116 | + if ( $options & RLH_FOR_UPDATE ) { |
| 4117 | + $query .= ' FOR UPDATE'; |
| 4118 | + } |
| 4119 | + |
| 4120 | + $res = $dbr->query( $query, $fname ); |
| 4121 | + |
| 4122 | + # Fetch data and form into an associative array |
| 4123 | + # non-existent = broken |
| 4124 | + while ( $s = $dbr->fetchObject($res) ) { |
| 4125 | + $title = Title::makeTitle( $s->page_namespace, $s->page_title ); |
| 4126 | + $pdbk = $title->getPrefixedDBkey(); |
| 4127 | + $linkCache->addGoodLinkObj( $s->page_id, $title, $s->page_len, $s->page_is_redirect ); |
| 4128 | + $this->mOutput->addLink( $title, $s->page_id ); |
| 4129 | + $colours[$pdbk] = $sk->getLinkColour( $title, $threshold ); |
| 4130 | + //add id to the extension todolist |
| 4131 | + $linkcolour_ids[$s->page_id] = $pdbk; |
| 4132 | + } |
| 4133 | + //pass an array of page_ids to an extension |
| 4134 | + wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) ); |
| 4135 | + } |
| 4136 | + wfProfileOut( $fname.'-check' ); |
| 4137 | + |
| 4138 | + # Do a second query for different language variants of links and categories |
| 4139 | + if($wgContLang->hasVariants()){ |
| 4140 | + $linkBatch = new LinkBatch(); |
| 4141 | + $variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders) |
| 4142 | + $categoryMap = array(); // maps $category_variant => $category (dbkeys) |
| 4143 | + $varCategories = array(); // category replacements oldDBkey => newDBkey |
| 4144 | + |
| 4145 | + $categories = $this->mOutput->getCategoryLinks(); |
| 4146 | + |
| 4147 | + // Add variants of links to link batch |
| 4148 | + foreach ( $this->mLinkHolders['namespaces'] as $key => $ns ) { |
| 4149 | + $title = $this->mLinkHolders['titles'][$key]; |
| 4150 | + if ( is_null( $title ) ) |
| 4151 | + continue; |
| 4152 | + |
| 4153 | + $pdbk = $title->getPrefixedDBkey(); |
| 4154 | + $titleText = $title->getText(); |
| 4155 | + |
| 4156 | + // generate all variants of the link title text |
| 4157 | + $allTextVariants = $wgContLang->convertLinkToAllVariants($titleText); |
| 4158 | + |
| 4159 | + // if link was not found (in first query), add all variants to query |
| 4160 | + if ( !isset($colours[$pdbk]) ){ |
| 4161 | + foreach($allTextVariants as $textVariant){ |
| 4162 | + if($textVariant != $titleText){ |
| 4163 | + $variantTitle = Title::makeTitle( $ns, $textVariant ); |
| 4164 | + if(is_null($variantTitle)) continue; |
| 4165 | + $linkBatch->addObj( $variantTitle ); |
| 4166 | + $variantMap[$variantTitle->getPrefixedDBkey()][] = $key; |
| 4167 | + } |
| 4168 | + } |
| 4169 | + } |
| 4170 | + } |
| 4171 | + |
| 4172 | + // process categories, check if a category exists in some variant |
| 4173 | + foreach( $categories as $category ){ |
| 4174 | + $variants = $wgContLang->convertLinkToAllVariants($category); |
| 4175 | + foreach($variants as $variant){ |
| 4176 | + if($variant != $category){ |
| 4177 | + $variantTitle = Title::newFromDBkey( Title::makeName(NS_CATEGORY,$variant) ); |
| 4178 | + if(is_null($variantTitle)) continue; |
| 4179 | + $linkBatch->addObj( $variantTitle ); |
| 4180 | + $categoryMap[$variant] = $category; |
| 4181 | + } |
| 4182 | + } |
| 4183 | + } |
| 4184 | + |
| 4185 | + |
| 4186 | + if(!$linkBatch->isEmpty()){ |
| 4187 | + // construct query |
| 4188 | + $titleClause = $linkBatch->constructSet('page', $dbr); |
| 4189 | + |
| 4190 | + $variantQuery = "SELECT page_id, page_namespace, page_title, page_is_redirect, page_len"; |
| 4191 | + |
| 4192 | + $variantQuery .= " FROM $page WHERE $titleClause"; |
| 4193 | + if ( $options & RLH_FOR_UPDATE ) { |
| 4194 | + $variantQuery .= ' FOR UPDATE'; |
| 4195 | + } |
| 4196 | + |
| 4197 | + $varRes = $dbr->query( $variantQuery, $fname ); |
| 4198 | + |
| 4199 | + // for each found variants, figure out link holders and replace |
| 4200 | + while ( $s = $dbr->fetchObject($varRes) ) { |
| 4201 | + |
| 4202 | + $variantTitle = Title::makeTitle( $s->page_namespace, $s->page_title ); |
| 4203 | + $varPdbk = $variantTitle->getPrefixedDBkey(); |
| 4204 | + $vardbk = $variantTitle->getDBkey(); |
| 4205 | + |
| 4206 | + $holderKeys = array(); |
| 4207 | + if(isset($variantMap[$varPdbk])){ |
| 4208 | + $holderKeys = $variantMap[$varPdbk]; |
| 4209 | + $linkCache->addGoodLinkObj( $s->page_id, $variantTitle, $s->page_len, $s->page_is_redirect ); |
| 4210 | + $this->mOutput->addLink( $variantTitle, $s->page_id ); |
| 4211 | + } |
| 4212 | + |
| 4213 | + // loop over link holders |
| 4214 | + foreach($holderKeys as $key){ |
| 4215 | + $title = $this->mLinkHolders['titles'][$key]; |
| 4216 | + if ( is_null( $title ) ) continue; |
| 4217 | + |
| 4218 | + $pdbk = $title->getPrefixedDBkey(); |
| 4219 | + |
| 4220 | + if(!isset($colours[$pdbk])){ |
| 4221 | + // found link in some of the variants, replace the link holder data |
| 4222 | + $this->mLinkHolders['titles'][$key] = $variantTitle; |
| 4223 | + $this->mLinkHolders['dbkeys'][$key] = $variantTitle->getDBkey(); |
| 4224 | + |
| 4225 | + // set pdbk and colour |
| 4226 | + $pdbks[$key] = $varPdbk; |
| 4227 | + $colours[$varPdbk] = $sk->getLinkColour( $variantTitle, $threshold ); |
| 4228 | + $linkcolour_ids[$s->page_id] = $pdbk; |
| 4229 | + } |
| 4230 | + wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) ); |
| 4231 | + } |
| 4232 | + |
| 4233 | + // check if the object is a variant of a category |
| 4234 | + if(isset($categoryMap[$vardbk])){ |
| 4235 | + $oldkey = $categoryMap[$vardbk]; |
| 4236 | + if($oldkey != $vardbk) |
| 4237 | + $varCategories[$oldkey]=$vardbk; |
| 4238 | + } |
| 4239 | + } |
| 4240 | + |
| 4241 | + // rebuild the categories in original order (if there are replacements) |
| 4242 | + if(count($varCategories)>0){ |
| 4243 | + $newCats = array(); |
| 4244 | + $originalCats = $this->mOutput->getCategories(); |
| 4245 | + foreach($originalCats as $cat => $sortkey){ |
| 4246 | + // make the replacement |
| 4247 | + if( array_key_exists($cat,$varCategories) ) |
| 4248 | + $newCats[$varCategories[$cat]] = $sortkey; |
| 4249 | + else $newCats[$cat] = $sortkey; |
| 4250 | + } |
| 4251 | + $this->mOutput->setCategoryLinks($newCats); |
| 4252 | + } |
| 4253 | + } |
| 4254 | + } |
| 4255 | + |
| 4256 | + # Construct search and replace arrays |
| 4257 | + wfProfileIn( $fname.'-construct' ); |
| 4258 | + $replacePairs = array(); |
| 4259 | + foreach ( $this->mLinkHolders['namespaces'] as $key => $ns ) { |
| 4260 | + $pdbk = $pdbks[$key]; |
| 4261 | + $searchkey = "<!--LINK $key-->"; |
| 4262 | + $title = $this->mLinkHolders['titles'][$key]; |
| 4263 | + if ( !isset( $colours[$pdbk] ) || $colours[$pdbk] == 'new' ) { |
| 4264 | + $linkCache->addBadLinkObj( $title ); |
| 4265 | + $colours[$pdbk] = 'new'; |
| 4266 | + $this->mOutput->addLink( $title, 0 ); |
| 4267 | + $replacePairs[$searchkey] = $sk->makeBrokenLinkObj( $title, |
| 4268 | + $this->mLinkHolders['texts'][$key], |
| 4269 | + $this->mLinkHolders['queries'][$key] ); |
| 4270 | + } else { |
| 4271 | + $replacePairs[$searchkey] = $sk->makeColouredLinkObj( $title, $colours[$pdbk], |
| 4272 | + $this->mLinkHolders['texts'][$key], |
| 4273 | + $this->mLinkHolders['queries'][$key] ); |
| 4274 | + } |
| 4275 | + } |
| 4276 | + $replacer = new HashtableReplacer( $replacePairs, 1 ); |
| 4277 | + wfProfileOut( $fname.'-construct' ); |
| 4278 | + |
| 4279 | + # Do the thing |
| 4280 | + wfProfileIn( $fname.'-replace' ); |
| 4281 | + $text = preg_replace_callback( |
| 4282 | + '/(<!--LINK .*?-->)/', |
| 4283 | + $replacer->cb(), |
| 4284 | + $text); |
| 4285 | + |
| 4286 | + wfProfileOut( $fname.'-replace' ); |
| 4287 | + } |
| 4288 | + |
| 4289 | + # Now process interwiki link holders |
| 4290 | + # This is quite a bit simpler than internal links |
| 4291 | + if ( !empty( $this->mInterwikiLinkHolders['texts'] ) ) { |
| 4292 | + wfProfileIn( $fname.'-interwiki' ); |
| 4293 | + # Make interwiki link HTML |
| 4294 | + $replacePairs = array(); |
| 4295 | + foreach( $this->mInterwikiLinkHolders['texts'] as $key => $link ) { |
| 4296 | + $title = $this->mInterwikiLinkHolders['titles'][$key]; |
| 4297 | + $replacePairs[$key] = $sk->link( $title, $link ); |
| 4298 | + } |
| 4299 | + $replacer = new HashtableReplacer( $replacePairs, 1 ); |
| 4300 | + |
| 4301 | + $text = preg_replace_callback( |
| 4302 | + '/<!--IWLINK (.*?)-->/', |
| 4303 | + $replacer->cb(), |
| 4304 | + $text ); |
| 4305 | + wfProfileOut( $fname.'-interwiki' ); |
| 4306 | + } |
| 4307 | + |
| 4308 | + wfProfileOut( $fname ); |
| 4309 | + return $colours; |
4033 | 4310 | } |
4034 | 4311 | |
4035 | 4312 | /** |
— | — | @@ -4038,10 +4315,39 @@ |
4039 | 4316 | * @return string |
4040 | 4317 | */ |
4041 | 4318 | function replaceLinkHoldersText( $text ) { |
4042 | | - return $this->mLinkHolders->replaceText( $text ); |
| 4319 | + $fname = 'Parser::replaceLinkHoldersText'; |
| 4320 | + wfProfileIn( $fname ); |
| 4321 | + |
| 4322 | + $text = preg_replace_callback( |
| 4323 | + '/<!--(LINK|IWLINK) (.*?)-->/', |
| 4324 | + array( &$this, 'replaceLinkHoldersTextCallback' ), |
| 4325 | + $text ); |
| 4326 | + |
| 4327 | + wfProfileOut( $fname ); |
| 4328 | + return $text; |
4043 | 4329 | } |
4044 | 4330 | |
4045 | 4331 | /** |
| 4332 | + * @param array $matches |
| 4333 | + * @return string |
| 4334 | + * @private |
| 4335 | + */ |
| 4336 | + function replaceLinkHoldersTextCallback( $matches ) { |
| 4337 | + $type = $matches[1]; |
| 4338 | + $key = $matches[2]; |
| 4339 | + if( $type == 'LINK' ) { |
| 4340 | + if( isset( $this->mLinkHolders['texts'][$key] ) ) { |
| 4341 | + return $this->mLinkHolders['texts'][$key]; |
| 4342 | + } |
| 4343 | + } elseif( $type == 'IWLINK' ) { |
| 4344 | + if( isset( $this->mInterwikiLinkHolders['texts'][$key] ) ) { |
| 4345 | + return $this->mInterwikiLinkHolders['texts'][$key]; |
| 4346 | + } |
| 4347 | + } |
| 4348 | + return $matches[0]; |
| 4349 | + } |
| 4350 | + |
| 4351 | + /** |
4046 | 4352 | * Tag hook handler for 'pre'. |
4047 | 4353 | */ |
4048 | 4354 | function renderPreTag( $text, $attribs ) { |
— | — | @@ -4092,7 +4398,7 @@ |
4093 | 4399 | |
4094 | 4400 | wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) ); |
4095 | 4401 | |
4096 | | - $lines = StringUtils::explode( "\n", $text ); |
| 4402 | + $lines = explode( "\n", $text ); |
4097 | 4403 | foreach ( $lines as $line ) { |
4098 | 4404 | # match lines like these: |
4099 | 4405 | # Image:someimage.jpg|This is some image |
— | — | @@ -4105,7 +4411,7 @@ |
4106 | 4412 | |
4107 | 4413 | if ( strpos( $matches[0], '%' ) !== false ) |
4108 | 4414 | $matches[1] = urldecode( $matches[1] ); |
4109 | | - $tp = Title::newFromText( $matches[1], NS_IMAGE ); |
| 4415 | + $tp = Title::newFromText( $matches[1] ); |
4110 | 4416 | $nt =& $tp; |
4111 | 4417 | if( is_null( $nt ) ) { |
4112 | 4418 | # Bogus title. Ignore these so we don't bomb out later. |
— | — | @@ -4171,11 +4477,8 @@ |
4172 | 4478 | |
4173 | 4479 | /** |
4174 | 4480 | * Parse image options text and use it to make an image |
4175 | | - * @param Title $title |
4176 | | - * @param string $options |
4177 | | - * @param LinkHolderArray $holders |
4178 | 4481 | */ |
4179 | | - function makeImage( $title, $options, $holders = false ) { |
| 4482 | + function makeImage( $title, $options ) { |
4180 | 4483 | # Check if the options text is of the form "options|alt text" |
4181 | 4484 | # Options are: |
4182 | 4485 | # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang |
— | — | @@ -4198,7 +4501,7 @@ |
4199 | 4502 | # * bottom |
4200 | 4503 | # * text-bottom |
4201 | 4504 | |
4202 | | - $parts = StringUtils::explode( "|", $options ); |
| 4505 | + $parts = array_map( 'trim', explode( '|', $options) ); |
4203 | 4506 | $sk = $this->mOptions->getSkin(); |
4204 | 4507 | |
4205 | 4508 | # Give extensions a chance to select the file revision for us |
— | — | @@ -4285,13 +4588,7 @@ |
4286 | 4589 | } |
4287 | 4590 | |
4288 | 4591 | # Strip bad stuff out of the alt text |
4289 | | - # We can't just use replaceLinkHoldersText() here, because if this function |
4290 | | - # is called from replaceInternalLinks2(), mLinkHolders won't be up to date. |
4291 | | - if ( $holders ) { |
4292 | | - $alt = $holders->replaceText( $caption ); |
4293 | | - } else { |
4294 | | - $alt = $this->replaceLinkHoldersText( $caption ); |
4295 | | - } |
| 4592 | + $alt = $this->replaceLinkHoldersText( $caption ); |
4296 | 4593 | |
4297 | 4594 | # make sure there are no placeholders in thumbnail attributes |
4298 | 4595 | # that are later expanded to html- so expand them now and |
Index: trunk/phase3/includes/Title.php |
— | — | @@ -10,6 +10,12 @@ |
11 | 11 | |
12 | 12 | define ( 'GAID_FOR_UPDATE', 1 ); |
13 | 13 | |
| 14 | +/** |
| 15 | + * Title::newFromText maintains a cache to avoid expensive re-normalization of |
| 16 | + * commonly used titles. On a batch operation this can become a memory leak |
| 17 | + * if not bounded. After hitting this many titles reset the cache. |
| 18 | + */ |
| 19 | +define( 'MW_TITLECACHE_MAX', 1000 ); |
14 | 20 | |
15 | 21 | /** |
16 | 22 | * Constants for pr_cascade bitfield |
— | — | @@ -30,14 +36,6 @@ |
31 | 37 | //@} |
32 | 38 | |
33 | 39 | /** |
34 | | - * Title::newFromText maintains a cache to avoid expensive re-normalization of |
35 | | - * commonly used titles. On a batch operation this can become a memory leak |
36 | | - * if not bounded. After hitting this many titles reset the cache. |
37 | | - */ |
38 | | - const CACHE_MAX = 1000; |
39 | | - |
40 | | - |
41 | | - /** |
42 | 40 | * @name Private member variables |
43 | 41 | * Please use the accessor functions instead. |
44 | 42 | * @private |
— | — | @@ -133,7 +131,7 @@ |
134 | 132 | static $cachedcount = 0 ; |
135 | 133 | if( $t->secureAndSplit() ) { |
136 | 134 | if( $defaultNamespace == NS_MAIN ) { |
137 | | - if( $cachedcount >= self::CACHE_MAX ) { |
| 135 | + if( $cachedcount >= MW_TITLECACHE_MAX ) { |
138 | 136 | # Avoid memory leaks on mass operations... |
139 | 137 | Title::$titleCache = array(); |
140 | 138 | $cachedcount=0; |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -66,7 +66,6 @@ |
67 | 67 | 'EnotifNotifyJob' => 'includes/EnotifNotifyJob.php', |
68 | 68 | 'ErrorPageError' => 'includes/Exception.php', |
69 | 69 | 'Exif' => 'includes/Exif.php', |
70 | | - 'ExplodeIterator' => 'includes/StringUtils.php', |
71 | 70 | 'ExternalEdit' => 'includes/ExternalEdit.php', |
72 | 71 | 'ExternalStoreDB' => 'includes/ExternalStoreDB.php', |
73 | 72 | 'ExternalStoreHttp' => 'includes/ExternalStoreHttp.php', |
— | — | @@ -357,7 +356,6 @@ |
358 | 357 | # includes/parser |
359 | 358 | 'CoreParserFunctions' => 'includes/parser/CoreParserFunctions.php', |
360 | 359 | 'DateFormatter' => 'includes/parser/DateFormatter.php', |
361 | | - 'LinkHolderArray' => 'includes/parser/LinkHolderArray.php', |
362 | 360 | 'OnlyIncludeReplacer' => 'includes/parser/Parser.php', |
363 | 361 | 'PPDAccum_Hash' => 'includes/parser/Preprocessor_Hash.php', |
364 | 362 | 'PPDPart' => 'includes/parser/Preprocessor_DOM.php', |
Index: trunk/phase3/includes/StringUtils.php |
— | — | @@ -167,18 +167,6 @@ |
168 | 168 | $string = str_replace( '$', '\\$', $string ); |
169 | 169 | return $string; |
170 | 170 | } |
171 | | - |
172 | | - /** |
173 | | - * Workalike for explode() with limited memory usage. |
174 | | - * Returns an Iterator |
175 | | - */ |
176 | | - static function explode( $separator, $subject ) { |
177 | | - if ( substr_count( $subject, $separator ) > 1000 ) { |
178 | | - return new ExplodeIterator( $separator, $subject ); |
179 | | - } else { |
180 | | - return new ArrayIterator( explode( $separator, $subject ) ); |
181 | | - } |
182 | | - } |
183 | 171 | } |
184 | 172 | |
185 | 173 | /** |
— | — | @@ -322,90 +310,3 @@ |
323 | 311 | return $result; |
324 | 312 | } |
325 | 313 | } |
326 | | - |
327 | | -/** |
328 | | - * An iterator which works exactly like: |
329 | | - * |
330 | | - * foreach ( explode( $delim, $s ) as $element ) { |
331 | | - * ... |
332 | | - * } |
333 | | - * |
334 | | - * Except it doesn't use 193 byte per element |
335 | | - */ |
336 | | -class ExplodeIterator implements Iterator { |
337 | | - // The subject string |
338 | | - var $subject, $subjectLength; |
339 | | - |
340 | | - // The delimiter |
341 | | - var $delim, $delimLength; |
342 | | - |
343 | | - // The position of the start of the line |
344 | | - var $curPos; |
345 | | - |
346 | | - // The position after the end of the next delimiter |
347 | | - var $endPos; |
348 | | - |
349 | | - // The current token |
350 | | - var $current; |
351 | | - |
352 | | - /** |
353 | | - * Construct a DelimIterator |
354 | | - */ |
355 | | - function __construct( $delim, $s ) { |
356 | | - $this->subject = $s; |
357 | | - $this->delim = $delim; |
358 | | - |
359 | | - // Micro-optimisation (theoretical) |
360 | | - $this->subjectLength = strlen( $s ); |
361 | | - $this->delimLength = strlen( $delim ); |
362 | | - |
363 | | - $this->rewind(); |
364 | | - } |
365 | | - |
366 | | - function rewind() { |
367 | | - $this->curPos = 0; |
368 | | - $this->endPos = strpos( $this->subject, $this->delim ); |
369 | | - $this->refreshCurrent(); |
370 | | - } |
371 | | - |
372 | | - |
373 | | - function refreshCurrent() { |
374 | | - if ( $this->curPos === false ) { |
375 | | - $this->current = false; |
376 | | - } elseif ( $this->curPos >= $this->subjectLength ) { |
377 | | - $this->current = ''; |
378 | | - } elseif ( $this->endPos === false ) { |
379 | | - $this->current = substr( $this->subject, $this->curPos ); |
380 | | - } else { |
381 | | - $this->current = substr( $this->subject, $this->curPos, $this->endPos - $this->curPos ); |
382 | | - } |
383 | | - } |
384 | | - |
385 | | - function current() { |
386 | | - return $this->current; |
387 | | - } |
388 | | - |
389 | | - function key() { |
390 | | - return $this->curPos; |
391 | | - } |
392 | | - |
393 | | - function next() { |
394 | | - if ( $this->endPos === false ) { |
395 | | - $this->curPos = false; |
396 | | - } else { |
397 | | - $this->curPos = $this->endPos + $this->delimLength; |
398 | | - if ( $this->curPos >= $this->subjectLength ) { |
399 | | - $this->endPos = false; |
400 | | - } else { |
401 | | - $this->endPos = strpos( $this->subject, $this->delim, $this->curPos ); |
402 | | - } |
403 | | - } |
404 | | - $this->refreshCurrent(); |
405 | | - return $this->current; |
406 | | - } |
407 | | - |
408 | | - function valid() { |
409 | | - return $this->curPos !== false; |
410 | | - } |
411 | | -} |
412 | | - |
Index: trunk/phase3/includes/MessageCache.php |
— | — | @@ -44,6 +44,7 @@ |
45 | 45 | |
46 | 46 | /** |
47 | 47 | * ParserOptions is lazy initialised. |
| 48 | + * Access should probably be protected. |
48 | 49 | */ |
49 | 50 | function getParserOptions() { |
50 | 51 | if ( !$this->mParserOptions ) { |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -130,7 +130,6 @@ |
131 | 131 | gives results |
132 | 132 | * Avoid recursive crazy expansions in section edit comments for pages which |
133 | 133 | contain '/*' in the title |
134 | | -* Fix excessive memory usage when parsing pages with lots of links |
135 | 134 | |
136 | 135 | === API changes in 1.14 === |
137 | 136 | |