This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace SUC; |
||
4 | |||
5 | use ParserOptions; |
||
6 | use ParserOutput; |
||
7 | use ApiBase; |
||
8 | use Title; |
||
9 | |||
10 | /** |
||
11 | * Content parsing can be expensive especially if it contains a large set of |
||
12 | * #ask queries/#if parser functions to form a summary card. |
||
13 | * |
||
14 | * This API module is to parse a text/template and if possible tries to retrieve |
||
15 | * data from a persistent cache layer to avoid unnecessary content parsing. |
||
16 | * |
||
17 | * On the event of NewRevisionFromEditComplete a cached item will be evicted if |
||
18 | * it matches the CacheHelper::getHashFrom. |
||
19 | * |
||
20 | * On the event that a template that was used for generating content was modified |
||
21 | * then a re-parse of the content is requested the next time instead of a cache |
||
22 | * retrieval. |
||
23 | * |
||
24 | * @license GNU GPL v2+ |
||
25 | * @since 1.0 |
||
26 | * |
||
27 | * @author mwjames |
||
28 | */ |
||
29 | class ApiSummaryCardContentParser extends ApiBase { |
||
30 | |||
31 | /** |
||
32 | * @var CacheHelper |
||
33 | */ |
||
34 | private $cacheHelper; |
||
35 | |||
36 | /** |
||
37 | * @since 1.0 |
||
38 | * |
||
39 | * @param CacheHelper $cacheHelper |
||
40 | */ |
||
41 | 4 | public function setCacheHelper( CacheHelper $cacheHelper ) { |
|
42 | 4 | $this->cacheHelper = $cacheHelper; |
|
43 | 4 | } |
|
44 | |||
45 | /** |
||
46 | * @since 1.0 |
||
47 | * |
||
48 | * @return CacheHelper |
||
49 | */ |
||
50 | 2 | public function getCacheHelper() { |
|
51 | |||
52 | 2 | if ( $this->cacheHelper !== null ) { |
|
53 | 2 | return $this->cacheHelper; |
|
54 | } |
||
55 | |||
56 | return $this->cacheHelper = CacheHelper::newFromOptions( |
||
57 | Options::newFromGlobals() |
||
58 | ); |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * ApiBase::execute |
||
63 | * |
||
64 | * @since 1.0 |
||
65 | */ |
||
66 | 3 | public function execute() { |
|
67 | |||
68 | 3 | $data = $this->getDataFrom( |
|
69 | 3 | $this->extractRequestParams() |
|
70 | 3 | ); |
|
71 | |||
72 | 3 | $this->getResult()->addValue( |
|
73 | 3 | null, |
|
74 | 3 | $this->getModuleName(), |
|
75 | $data |
||
76 | 3 | ); |
|
77 | 3 | } |
|
78 | |||
79 | /** |
||
80 | * ApiBase::getAllowedParams |
||
81 | * |
||
82 | * @since 1.0 |
||
83 | */ |
||
84 | 3 | public function getAllowedParams() { |
|
85 | return array( |
||
86 | 3 | 'text' => array( ApiBase::PARAM_TYPE => 'string' ), |
|
87 | 3 | 'template' => array( ApiBase::PARAM_TYPE => 'string' ), |
|
88 | 3 | 'title' => array( ApiBase::PARAM_TYPE => 'string' ), |
|
89 | 3 | 'userlanguage' => array( ApiBase::PARAM_TYPE => 'string' ) |
|
90 | 3 | ); |
|
91 | 1 | } |
|
92 | |||
93 | /** |
||
94 | * @codeCoverageIgnore |
||
95 | * @see ApiBase::getParamDescription |
||
96 | * |
||
97 | * @return array |
||
98 | */ |
||
99 | public function getParamDescription() { |
||
100 | return array( |
||
101 | 'text' => 'Contains the text/template to be parsed.', |
||
102 | 'template' => 'Contains the template to track possible changes.', |
||
103 | 'title' => 'Subject to filter repeated requests.', |
||
104 | 'userlanguage' => 'The user language.' |
||
105 | ); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * @codeCoverageIgnore |
||
110 | * @see ApiBase::getDescription |
||
111 | * |
||
112 | * @return array |
||
113 | */ |
||
114 | public function getDescription() { |
||
115 | return array( |
||
116 | 'Module to parse raw text/templates and store returning results using a persistent cache, if available.' |
||
117 | ); |
||
118 | } |
||
119 | |||
120 | 3 | private function getDataFrom( array $params ) { |
|
121 | |||
122 | 3 | $start = microtime( true ); |
|
123 | 3 | $isUntouchedTemplate = false; |
|
124 | |||
125 | $data = array( |
||
126 | 3 | 'text' => '', |
|
127 | 'time' => false |
||
128 | 3 | ); |
|
129 | |||
130 | 3 | if ( !isset( $params['text'] ) || !isset( $params['title'] ) ) { |
|
131 | 1 | return $data; |
|
132 | } |
||
133 | |||
134 | 2 | $blobStore = $this->getCacheHelper()->getBlobStore(); |
|
135 | |||
136 | 2 | list( $templateKey, $templateTouched ) = $this->getTemplateInfoFrom( |
|
137 | $params |
||
138 | 2 | ); |
|
139 | |||
140 | 2 | $title = $this->getCacheHelper()->newTitleFromText( |
|
141 | 2 | $params['title'] |
|
142 | 2 | ); |
|
143 | |||
144 | 2 | $hash = $this->getCacheHelper()->getHashFrom( $title ); |
|
145 | |||
146 | 2 | $container = $blobStore->read( $hash ); |
|
147 | |||
148 | // If the template was touched then re-parse the content to |
||
149 | // avoid stalled data |
||
150 | 2 | if ( $container->has( $templateKey ) ) { |
|
151 | 1 | $isUntouchedTemplate = $container->get( $templateKey ) == $templateTouched; |
|
152 | 1 | } |
|
153 | |||
154 | // Split by lang and fragment into separate containers, while the cache |
||
155 | // is stored on a per subject basis allowing all related containers to |
||
156 | // be purged at once |
||
157 | 2 | $contentByLanguageKey = 'L#' . $params['userlanguage'] . '#' . ( $title !== null ? $title->getFragment() : '' ); |
|
158 | |||
159 | 2 | if ( $isUntouchedTemplate && $hash !== '' && $container->has( $contentByLanguageKey ) ) { |
|
160 | 1 | wfDebugLog( 'smw', 'SummaryCards API cache hit on ' . $hash ); |
|
161 | 1 | $data = $container->get( $contentByLanguageKey ); |
|
162 | 1 | $data['time']['cached'] = microtime( true ) - $start; |
|
163 | 1 | return $data; |
|
164 | } |
||
165 | |||
166 | $data = array( |
||
167 | 1 | 'text' => $this->doParse( $title, $params['userlanguage'], $params['text'] ), |
|
168 | 'time' => array( |
||
169 | 1 | 'parse' => microtime( true ) - $start |
|
170 | 1 | ) |
|
171 | 1 | ); |
|
172 | |||
173 | // Only cache when a template is known |
||
174 | 1 | if ( $hash !== '' && $templateKey !== '' ) { |
|
175 | $container->set( $contentByLanguageKey, $data ); |
||
176 | $container->set( $templateKey, $templateTouched ); |
||
177 | $blobStore->save( $container ); |
||
178 | } |
||
179 | |||
180 | 1 | return $data; |
|
181 | } |
||
182 | |||
183 | 2 | private function getTemplateInfoFrom( $params ) { |
|
184 | |||
185 | 2 | $templateKey = ''; |
|
186 | 2 | $templateTouched = 0; |
|
187 | |||
188 | 2 | if ( isset( $params['template'] ) ) { |
|
189 | 1 | $template = Title::makeTitleSafe( NS_TEMPLATE, $params['template'] ); |
|
190 | 1 | $templateTouched = $template->getTouched(); |
|
191 | 1 | $templateKey = 'T#' . $params['template'] . '#' . $params['userlanguage']; |
|
192 | 1 | } |
|
193 | |||
194 | 2 | return array( $templateKey, $templateTouched ); |
|
195 | } |
||
196 | |||
197 | 1 | private function doParse( $title, $userLanguage, $text ) { |
|
198 | |||
199 | 1 | $parserOutput = $GLOBALS['wgParser']->parse( |
|
200 | 1 | $text, |
|
201 | 1 | $title, |
|
202 | 1 | $this->makeParserOptions( $title, $userLanguage ) |
|
203 | 1 | ); |
|
204 | |||
205 | 1 | return $parserOutput instanceof ParserOutput ? $parserOutput->getText() : '' ; |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
206 | } |
||
207 | |||
208 | 1 | private function makeParserOptions( $title, $userLanguage ) { |
|
209 | |||
210 | 1 | $user = null; |
|
211 | |||
212 | 1 | $parserOptions = new ParserOptions( $user ); |
|
213 | 1 | $parserOptions->setInterfaceMessage( true ); |
|
214 | 1 | $parserOptions->setUserLang( $userLanguage ); |
|
215 | |||
216 | // Ensure that no dependency processing occurs with the #ask being |
||
217 | // bound to the template output and not to the context page |
||
218 | 1 | $parserOptions->smwAskNoDependencyTracking = true; |
|
219 | |||
220 | 1 | return $parserOptions; |
|
221 | } |
||
222 | |||
223 | } |
||
224 |