Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 45 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
MissingExtensionException | |
0.00% |
0 / 44 |
|
0.00% |
0 / 5 |
210 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
renderHtml | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
20 | |||
renderText | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
render | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getMWLogo | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Registration; |
4 | |
5 | use Exception; |
6 | use HttpStatus; |
7 | use MediaWiki\Html\TemplateParser; |
8 | use Wikimedia\ObjectCache\EmptyBagOStuff; |
9 | |
10 | /** |
11 | * Thrown when ExtensionRegistry cannot open the extension.json or skin.json file. |
12 | * |
13 | * We handle this case specially, because it is one of the more |
14 | * common errors a new MW sysadmin is likely to encounter and we |
15 | * want their initial experience to be good. wfLoadExtension() |
16 | * generally happens before MWExceptionRenderer gets installed |
17 | * so we cannot use that. |
18 | * |
19 | * @ingroup ExtensionRegistry |
20 | * @internal |
21 | */ |
22 | class MissingExtensionException extends Exception { |
23 | private bool $isSkin; |
24 | private string $extName = 'unknown'; |
25 | private string $path; |
26 | private string $error; |
27 | |
28 | /** |
29 | * @param string $path Path of file that cannot be read |
30 | * @param string $error Text of error mtime gave |
31 | */ |
32 | public function __construct( string $path, string $error ) { |
33 | $this->isSkin = str_ends_with( $path, "/skin.json" ); |
34 | $m = []; |
35 | preg_match( "!/([^/]*)/[^/]*.json$!", $path, $m ); |
36 | if ( $m ) { |
37 | $this->extName = $m[1]; |
38 | } |
39 | $this->path = $path; |
40 | $this->error = $error; |
41 | |
42 | parent::__construct( "Error Loading extension. Unable to open file $path: $error" ); |
43 | } |
44 | |
45 | /** |
46 | * Output error message as html. |
47 | * |
48 | * Avoid relying on MW stuff, as it might not be setup yet. |
49 | * We don't bother translating, as the user may not have even set lang yet. |
50 | * |
51 | */ |
52 | private function renderHtml() { |
53 | if ( !headers_sent() ) { |
54 | HttpStatus::header( 500 ); |
55 | header( 'Content-Type: text/html; charset=UTF-8' ); |
56 | } |
57 | |
58 | $templateParser = new TemplateParser( null, new EmptyBagOStuff() ); |
59 | |
60 | try { |
61 | echo $templateParser->processTemplate( |
62 | 'ExtensionConfigError', |
63 | [ |
64 | 'version' => MW_VERSION, |
65 | 'path' => $this->path, |
66 | 'type' => $this->isSkin ? 'skin' : 'extension', |
67 | 'error' => $this->error, |
68 | 'extName' => $this->extName, |
69 | 'trace' => $this->getTraceAsString(), |
70 | 'mwLogo' => $this->getMWLogo(), |
71 | ] |
72 | ); |
73 | } catch ( Exception $e ) { |
74 | echo 'Error: ' . htmlspecialchars( $e->getMessage() ); |
75 | } |
76 | } |
77 | |
78 | /** |
79 | * Render the error for CLI |
80 | */ |
81 | private function renderText() { |
82 | $type = $this->isSkin ? 'skin' : 'extension'; |
83 | echo "Error: The $this->extName $type cannot be loaded. " |
84 | . "Check that all of its files are installed properly.\n\n"; |
85 | echo $this->getTraceAsString(); |
86 | echo "\n"; |
87 | } |
88 | |
89 | /** |
90 | * Output an error response and exit. |
91 | * |
92 | * @return never |
93 | */ |
94 | public function render() { |
95 | if ( wfIsCli() ) { |
96 | $this->renderText(); |
97 | } else { |
98 | $this->renderHtml(); |
99 | } |
100 | // Make sure that the error gets into logs. |
101 | // This will also stop execution. |
102 | trigger_error( $this->getMessage(), E_USER_ERROR ); |
103 | } |
104 | |
105 | /** |
106 | * Get the url for the MW logo |
107 | * |
108 | * @return string |
109 | */ |
110 | private function getMWLogo() { |
111 | global $wgResourceBasePath; |
112 | $suffix = "/resources/assets/mediawiki.png"; |
113 | if ( $wgResourceBasePath !== null ) { |
114 | // We are early in setup, so we can't rely on this. |
115 | return $wgResourceBasePath . $suffix; |
116 | } |
117 | $path = '/'; |
118 | foreach ( array_filter( explode( '/', $_SERVER['PHP_SELF'] ) ) as $part ) { |
119 | if ( !preg_match( '/\.php$/', $part ) ) { |
120 | $path .= "$part/"; |
121 | } else { |
122 | break; |
123 | } |
124 | } |
125 | |
126 | return $path . $suffix; |
127 | } |
128 | } |
129 | |
130 | /** @deprecated class alias since 1.43 */ |
131 | class_alias( MissingExtensionException::class, 'MissingExtensionException' ); |