MediaWiki REL1_37
HtmlCacheUpdater.php
Go to the documentation of this file.
1<?php
25
38 private $cdnMaxAge;
39
41 private $hookRunner;
42
44 public const PURGE_NAIVE = 0;
50 public const PURGE_PRESEND = 1;
55 public const PURGE_REBOUND = 2;
56
65 public const PURGE_INTENT_TXROUND_REFLECTED = self::PURGE_PRESEND | self::PURGE_REBOUND;
66
75 public const PURGE_URLS_LINKSUPDATE_ONLY = 4;
76
83 public const UNLESS_CACHE_MTIME_AFTER = 'unless-timestamp-exceeds';
84
87
97 public function __construct(
98 HookContainer $hookContainer,
99 TitleFactory $titleFactory,
100 $reboundDelay,
101 $useFileCache,
102 $cdnMaxAge
103 ) {
104 $this->hookRunner = new HookRunner( $hookContainer );
105 $this->titleFactory = $titleFactory;
106 $this->reboundDelay = $reboundDelay;
107 $this->useFileCache = $useFileCache;
108 $this->cdnMaxAge = $cdnMaxAge;
109 }
110
116 private function fieldHasFlag( $flags, $flag ) {
117 return ( ( $flags & $flag ) === $flag );
118 }
119
128 public function purgeUrls( $urls, $flags = self::PURGE_PRESEND, array $unless = [] ) {
129 $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
130 if ( $minFreshCacheMtime && time() > ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
131 return;
132 }
133
134 $urls = is_string( $urls ) ? [ $urls ] : $urls;
135
136 $reboundDelay = $this->fieldHasFlag( $flags, self::PURGE_REBOUND )
137 ? $this->reboundDelay
138 : 0; // no second purge
139
140 $update = new CdnCacheUpdate( $urls, [ 'reboundDelay' => $reboundDelay ] );
141 if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
142 DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
143 } else {
144 $update->doUpdate();
145 }
146 }
147
160 public function purgeTitleUrls( $pages, $flags = self::PURGE_PRESEND, array $unless = [] ) {
161 $pages = is_iterable( $pages ) ? $pages : [ $pages ];
162 $pageIdentities = [];
163
164 foreach ( $pages as $page ) {
165 // TODO: We really only need to cast to PageIdentity. We could use a LinkBatch for that.
166 $title = $this->titleFactory->castFromPageReference( $page );
167
168 if ( $title->canExist() ) {
169 $pageIdentities[] = $title;
170 }
171 }
172
173 if ( !$pageIdentities ) {
174 return;
175 }
176
177 if ( $this->useFileCache ) {
178 $update = HtmlFileCacheUpdate::newFromPages( $pageIdentities );
179 if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
180 DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
181 } else {
182 $update->doUpdate();
183 }
184 }
185
186 $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
187 if ( !$minFreshCacheMtime || time() <= ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
188 $urls = [];
189 foreach ( $pageIdentities as $pi ) {
191 $urls = array_merge( $urls, $this->getUrls( $pi, $flags ) );
192 }
193 $this->purgeUrls( $urls, $flags );
194 }
195 }
196
204 public function getUrls( PageReference $page, int $flags = 0 ): array {
205 $title = $this->titleFactory->castFromPageReference( $page );
206
207 if ( !$title->canExist() ) {
208 return [];
209 }
210
211 // These urls are affected both by direct revisions as well,
212 // as re-rendering of the same content during a LinksUpdate.
213 $urls = [
214 $title->getInternalURL()
215 ];
216 // Language variant page views are currently not cached
217 // and thus not purged (T250511).
218
219 // These urls are only affected by direct revisions, and do not require
220 // purging when a LinksUpdate merely rerenders the same content.
221 // This exists to avoid large amounts of redundant PURGE traffic (T250261).
222 if ( !$this->fieldHasFlag( $flags, self::PURGE_URLS_LINKSUPDATE_ONLY ) ) {
223 $urls[] = $title->getInternalURL( 'action=history' );
224
225 // Canonical action=raw URLs for user and site config pages (T58874, T261371).
226 if ( $title->isUserJsConfigPage() || $title->isSiteJsConfigPage() ) {
227 $urls[] = $title->getInternalURL( 'action=raw&ctype=text/javascript' );
228 } elseif ( $title->isUserJsonConfigPage() || $title->isSiteJsonConfigPage() ) {
229 $urls[] = $title->getInternalURL( 'action=raw&ctype=application/json' );
230 } elseif ( $title->isUserCssConfigPage() || $title->isSiteCssConfigPage() ) {
231 $urls[] = $title->getInternalURL( 'action=raw&ctype=text/css' );
232 }
233 }
234
235 // Extensions may add novel ways to access this content
236 $append = [];
237 $mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
238 $this->hookRunner->onHtmlCacheUpdaterAppendUrls( $title, $mode, $append );
239 $urls = array_merge( $urls, $append );
240
241 // Extensions may add novel ways to access the site overall
242 $append = [];
243 $this->hookRunner->onHtmlCacheUpdaterVaryUrls( $urls, $append );
244 $urls = array_merge( $urls, $append );
245
246 // Legacy. TODO: Deprecate this
247 $this->hookRunner->onTitleSquidURLs( $title, $urls );
248
249 return $urls;
250 }
251}
Handles purging the appropriate CDN objects given a list of URLs or Title instances.
Class to invalidate the CDN and HTMLFileCache entries associated with URLs/titles.
int $useFileCache
Whether filesystem-based HTML output caching is enabled.
int $cdnMaxAge
Max seconds for CDN to served cached objects without revalidation.
purgeUrls( $urls, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN for a URL or list of URLs.
fieldHasFlag( $flags, $flag)
int $reboundDelay
Seconds between initial and rebound purges; 0 if disabled.
getUrls(PageReference $page, int $flags=0)
Get a list of URLs to purge from the CDN cache when this page changes.
purgeTitleUrls( $pages, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN/HTMLFileCache for a title or the titles yielded by an iterator.
__construct(HookContainer $hookContainer, TitleFactory $titleFactory, $reboundDelay, $useFileCache, $cdnMaxAge)
TitleFactory $titleFactory
static newFromPages( $pages)
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Creates Title objects.
Interface for objects (potentially) representing an editable wiki page.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.