66 $this->tmpParentDir =
"{$this->libDir}/.foreign/tmp";
68 $cacheHome = getenv(
'XDG_CACHE_HOME' ) ? realpath( getenv(
'XDG_CACHE_HOME' ) ) :
false;
69 $this->cacheDir = $cacheHome ?
"$cacheHome/mw-foreign" :
"{$this->libDir}/.foreign/cache";
77 $actions = [
'update',
'verify',
'make-sri' ];
78 if ( !in_array(
$action, $actions ) ) {
79 $this->
error(
"Invalid action.\n\nMust be one of " . implode(
', ', $actions ) .
'.' );
84 $this->registry = $this->
parseBasicYaml( file_get_contents( $this->registryFile ) );
85 if ( $module ===
'all' ) {
87 } elseif ( isset( $this->registry[ $module ] ) ) {
88 $modules = [ $module => $this->registry[ $module ] ];
90 $this->
error(
"Unknown module name.\n\nMust be one of:\n" .
91 wordwrap( implode(
', ', array_keys( $this->registry ) ), 80 ) .
98 $this->
verbose(
"\n### {$moduleName}\n\n" );
99 $destDir =
"{$this->libDir}/$moduleName";
101 if ( $this->action ===
'update' ) {
102 $this->
output(
"... updating '{$moduleName}'\n" );
103 $this->
verbose(
"... emptying directory for $moduleName\n" );
105 } elseif ( $this->action ===
'verify' ) {
106 $this->
output(
"... verifying '{$moduleName}'\n" );
108 $this->
output(
"... checking '{$moduleName}'\n" );
111 $this->
verbose(
"... preparing {$this->tmpParentDir}\n" );
114 throw new Exception(
"Unable to create {$this->tmpParentDir}" );
117 if ( !isset( $info[
'type'] ) ) {
118 throw new Exception(
"Module '$moduleName' must have a 'type' key." );
120 switch ( $info[
'type'] ) {
131 throw new Exception(
"Unknown type '{$info['type']}' for '$moduleName'" );
135 $this->
output(
"\nDone!\n" );
137 if ( $this->hasErrors ) {
146 $key = basename( $src ) .
'_' . substr( $integrity, -12 );
147 $key = preg_replace(
'/[.\/+?=_-]+/',
'_', $key );
148 return rtrim( $key,
'_' );
153 return Wikimedia\quietCall(
'file_get_contents',
"{$this->cacheDir}/$key.data" );
158 file_put_contents(
"{$this->cacheDir}/$key.data",
$data, LOCK_EX );
161 private function fetch( $src, $integrity ) {
162 $key = $this->
cacheKey( $src, $integrity );
168 $req = MWHttpRequest::factory( $src, [
'method' =>
'GET',
'followRedirects' =>
false ] );
169 if ( !
$req->execute()->isOK() ) {
170 throw new Exception(
"Failed to download resource at {$src}" );
172 if (
$req->getStatus() !== 200 ) {
173 throw new Exception(
"Unexpected HTTP {$req->getStatus()} response from {$src}" );
176 $algo = $integrity ===
null ? $this->defaultAlgo : explode(
'-', $integrity )[0];
177 $actualIntegrity = $algo .
'-' . base64_encode( hash( $algo,
$data,
true ) );
178 if ( $integrity === $actualIntegrity ) {
179 $this->
verbose(
"... passed integrity check for {$src}\n" );
181 } elseif ( $this->action ===
'make-sri' ) {
182 $this->
output(
"Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
184 throw new Exception(
"Integrity check failed for {$src}\n" .
185 "\tExpected: {$integrity}\n" .
186 "\tActual: {$actualIntegrity}"
193 if ( !isset( $info[
'src'] ) ) {
194 throw new Exception(
"Module '$moduleName' must have a 'src' key." );
196 $data = $this->
fetch( $info[
'src'], $info[
'integrity'] ??
null );
197 $dest = $info[
'dest'] ?? basename( $info[
'src'] );
198 $path =
"$destDir/$dest";
199 if ( $this->action ===
'verify' && sha1_file(
$path ) !== sha1(
$data ) ) {
200 throw new Exception(
"File for '$moduleName' is different." );
202 if ( $this->action ===
'update' ) {
204 file_put_contents(
"$destDir/$dest",
$data );
209 if ( !isset( $info[
'files'] ) ) {
210 throw new Exception(
"Module '$moduleName' must have a 'files' key." );
212 foreach ( $info[
'files']
as $dest =>
$file ) {
213 if ( !isset(
$file[
'src'] ) ) {
214 throw new Exception(
"Module '$moduleName' file '$dest' must have a 'src' key." );
217 $path =
"$destDir/$dest";
218 if ( $this->action ===
'verify' && sha1_file(
$path ) !== sha1(
$data ) ) {
219 throw new Exception(
"File '$dest' for '$moduleName' is different." );
220 } elseif ( $this->action ===
'update' ) {
222 file_put_contents(
"$destDir/$dest",
$data );
228 $info += [
'src' =>
null,
'integrity' =>
null,
'dest' =>
null ];
229 if ( $info[
'src'] ===
null ) {
230 throw new Exception(
"Module '$moduleName' must have a 'src' key." );
233 $data = $this->
fetch( $info[
'src'], $info[
'integrity' ] );
234 $tmpFile =
"{$this->tmpParentDir}/$moduleName.tar";
235 $this->
verbose(
"... writing '$moduleName' src to $tmpFile\n" );
236 file_put_contents( $tmpFile,
$data );
237 $p =
new PharData( $tmpFile );
238 $tmpDir =
"{$this->tmpParentDir}/$moduleName";
239 $p->extractTo( $tmpDir );
242 if ( $info[
'dest'] ===
null ) {
244 $toCopy = [ $tmpDir => $destDir ];
248 foreach ( $info[
'dest']
as $fromSubPath => $toSubPath ) {
250 $fromPaths = glob(
"{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
252 throw new Exception(
"Path '$fromSubPath' of '$moduleName' not found." );
254 foreach ( $fromPaths
as $fromPath ) {
255 $toCopy[$fromPath] = $toSubPath ===
null
256 ?
"$destDir/" . basename( $fromPath )
257 :
"$destDir/$toSubPath/" . basename( $fromPath );
261 foreach ( $toCopy
as $from => $to ) {
262 if ( $this->action ===
'verify' ) {
263 $this->
verbose(
"... verifying $to\n" );
264 if ( is_dir( $from ) ) {
265 $rii =
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
267 RecursiveDirectoryIterator::SKIP_DOTS
271 $remote =
$file->getPathname();
272 $local = strtr( $remote, [ $from => $to ] );
273 if ( sha1_file( $remote ) !== sha1_file( $local ) ) {
274 $this->
error(
"File '$local' is different." );
275 $this->hasErrors =
true;
278 } elseif ( sha1_file( $from ) !== sha1_file( $to ) ) {
279 $this->
error(
"File '$to' is different." );
280 $this->hasErrors =
true;
282 } elseif ( $this->action ===
'update' ) {
283 $this->
verbose(
"... moving $from to $to\n" );
285 if ( !rename( $from, $to ) ) {
286 throw new Exception(
"Could not move $from to $to." );
309 foreach ( $this->registry
as $info ) {
310 if ( $info[
'type'] ===
'file' || $info[
'type'] ===
'tar' ) {
311 $knownKeys[] = $this->
cacheKey( $info[
'src'], $info[
'integrity'] );
312 } elseif ( $info[
'type'] ===
'multi-file' ) {
313 foreach ( $info[
'files']
as $file ) {
314 $knownKeys[] = $this->
cacheKey( $file[
'src'],
$file[
'integrity'] );
318 foreach ( glob(
"{$this->cacheDir}/*" )
as $cacheFile ) {
319 if ( !in_array( basename( $cacheFile,
'.data' ), $knownKeys ) ) {
320 unlink( $cacheFile );
341 $trimmed = ltrim( $text,
' ' );
342 if ( $trimmed ===
'' || $trimmed[0] ===
'#' ) {
345 $indent = strlen( $text ) - strlen( $trimmed );
346 if ( $indent % 2 !== 0 ) {
347 throw new Exception( __METHOD__ .
": Odd indentation on line $line." );
349 $depth = $indent === 0 ? 0 : ( $indent / 2 );
350 if ( $depth < $prev ) {
352 array_splice( $stack, $depth + 1 );
354 if ( !array_key_exists( $depth, $stack ) ) {
355 throw new Exception( __METHOD__ .
": Too much indentation on line $line." );
357 if ( strpos( $trimmed,
':' ) ===
false ) {
358 throw new Exception( __METHOD__ .
": Missing colon on line $line." );
360 $dest =& $stack[ $depth ];
361 if ( $dest ===
null ) {
365 list( $key, $val ) = explode(
':', $trimmed, 2 );
366 $val = ltrim( $val,
' ' );
369 $dest[ $key ] = $val;
374 $dest[ $key ] = &$val;
377 unset( $dest, $val );
wfRecursiveRemoveDir( $dir)
Remove a directory and all its content.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
Manage foreign resources registered with ResourceLoader.
cacheKey( $src, $integrity)
parseBasicYaml( $input)
Basic YAML parser.
handleTypeTar( $moduleName, $destDir, array $info)
handleTypeMultiFile( $moduleName, $destDir, array $info)
__construct( $registryFile, $libDir, callable $infoPrinter=null, callable $errorPrinter=null, callable $verbosePrinter=null)
handleTypeFile( $moduleName, $destDir, array $info)
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
this hook is for auditing only $req
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
if(is_array($mode)) switch( $mode) $input
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file