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 | declare( strict_types = 1 ); |
||
4 | |||
5 | namespace Wikibase\Repo\Api; |
||
6 | |||
7 | use ApiBase; |
||
8 | use ApiMain; |
||
9 | use ApiUsageException; |
||
10 | use Exception; |
||
11 | use InvalidArgumentException; |
||
12 | use LogicException; |
||
13 | use Wikibase\DataModel\Entity\EntityIdParser; |
||
14 | use Wikibase\DataModel\Entity\EntityIdParsingException; |
||
15 | use Wikibase\DataModel\Entity\ItemId; |
||
16 | use Wikibase\Lib\Store\EntityRevision; |
||
17 | use Wikibase\Repo\ChangeOp\ChangeOpsMerge; |
||
18 | use Wikibase\Repo\Interactors\ItemMergeException; |
||
19 | use Wikibase\Repo\Interactors\ItemMergeInteractor; |
||
20 | use Wikibase\Repo\Interactors\RedirectCreationException; |
||
21 | use Wikibase\Repo\WikibaseRepo; |
||
22 | |||
23 | /** |
||
24 | * @license GPL-2.0-or-later |
||
25 | * @author Addshore |
||
26 | * @author Daniel Kinzler |
||
27 | * @author Lucie-Aimée Kaffee |
||
28 | */ |
||
29 | class MergeItems extends ApiBase { |
||
30 | |||
31 | /** |
||
32 | * @var EntityIdParser |
||
33 | */ |
||
34 | private $idParser; |
||
35 | |||
36 | /** |
||
37 | * @var ApiErrorReporter |
||
38 | */ |
||
39 | private $errorReporter; |
||
40 | |||
41 | /** |
||
42 | * @var ItemMergeInteractor |
||
43 | */ |
||
44 | private $interactor; |
||
45 | |||
46 | /** |
||
47 | * @var ResultBuilder |
||
48 | */ |
||
49 | private $resultBuilder; |
||
50 | |||
51 | /** |
||
52 | * @see ApiBase::__construct |
||
53 | * |
||
54 | * @param ApiMain $mainModule |
||
55 | * @param string $moduleName |
||
56 | * @param EntityIdParser $idParser |
||
57 | * @param ItemMergeInteractor $interactor |
||
58 | * @param ApiErrorReporter $errorReporter |
||
59 | * @param callable $resultBuilderInstantiator |
||
60 | */ |
||
61 | public function __construct( |
||
62 | ApiMain $mainModule, |
||
63 | string $moduleName, |
||
64 | EntityIdParser $idParser, |
||
65 | ItemMergeInteractor $interactor, |
||
66 | ApiErrorReporter $errorReporter, |
||
67 | callable $resultBuilderInstantiator |
||
68 | ) { |
||
69 | parent::__construct( $mainModule, $moduleName ); |
||
70 | |||
71 | $this->idParser = $idParser; |
||
72 | $this->interactor = $interactor; |
||
73 | |||
74 | $this->errorReporter = $errorReporter; |
||
75 | $this->resultBuilder = $resultBuilderInstantiator( $this ); |
||
76 | } |
||
77 | |||
78 | public static function factory( ApiMain $mainModule, string $moduleName ): self { |
||
79 | $wikibaseRepo = WikibaseRepo::getDefaultInstance(); |
||
80 | $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $mainModule->getContext() ); |
||
81 | |||
82 | return new self( |
||
83 | $mainModule, |
||
84 | $moduleName, |
||
85 | $wikibaseRepo->getEntityIdParser(), |
||
86 | $wikibaseRepo->newItemMergeInteractor( $mainModule->getContext() ), |
||
87 | $apiHelperFactory->getErrorReporter( $mainModule ), |
||
88 | function ( $module ) use ( $apiHelperFactory ) { |
||
89 | return $apiHelperFactory->getResultBuilder( $module ); |
||
90 | } |
||
91 | ); |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * @param array $parameters |
||
96 | * @param string $name |
||
97 | * |
||
98 | * @return ItemId |
||
99 | * @throws ApiUsageException if the given parameter is not a valid ItemId |
||
100 | * @throws LogicException |
||
101 | */ |
||
102 | private function getItemIdParam( array $parameters, string $name ): ItemId { |
||
103 | if ( !isset( $parameters[$name] ) ) { |
||
104 | $this->errorReporter->dieWithError( [ 'param-missing', $name ], 'param-missing' ); |
||
105 | } |
||
106 | |||
107 | $value = $parameters[$name]; |
||
108 | |||
109 | try { |
||
110 | return new ItemId( $value ); |
||
111 | } catch ( InvalidArgumentException $ex ) { |
||
112 | $this->errorReporter->dieError( $ex->getMessage(), 'invalid-entity-id' ); |
||
0 ignored issues
–
show
|
|||
113 | throw new LogicException( 'ApiErrorReporter::dieError did not throw an exception' ); |
||
114 | } |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * @inheritDoc |
||
119 | */ |
||
120 | public function execute(): void { |
||
121 | $params = $this->extractRequestParams(); |
||
122 | |||
123 | try { |
||
124 | $fromId = $this->getItemIdParam( $params, 'fromid' ); |
||
125 | $toId = $this->getItemIdParam( $params, 'toid' ); |
||
126 | |||
127 | $ignoreConflicts = $params['ignoreconflicts']; |
||
128 | $summary = $params['summary']; |
||
129 | |||
130 | if ( $ignoreConflicts === null ) { |
||
131 | $ignoreConflicts = []; |
||
132 | } |
||
133 | |||
134 | $this->mergeItems( $fromId, $toId, $ignoreConflicts, $summary, $params['bot'] ); |
||
135 | } catch ( EntityIdParsingException $ex ) { |
||
136 | $this->errorReporter->dieException( $ex, 'invalid-entity-id' ); |
||
137 | } catch ( ItemMergeException $ex ) { |
||
138 | $this->handleException( $ex, $ex->getErrorCode() ); |
||
139 | } catch ( RedirectCreationException $ex ) { |
||
140 | $this->handleException( $ex, $ex->getErrorCode() ); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @param ItemId $fromId |
||
146 | * @param ItemId $toId |
||
147 | * @param string[] $ignoreConflicts |
||
148 | * @param string|null $summary |
||
149 | * @param bool $bot |
||
150 | * @throws ItemMergeException |
||
151 | * @throws RedirectCreationException |
||
152 | */ |
||
153 | private function mergeItems( ItemId $fromId, ItemId $toId, array $ignoreConflicts, ?string $summary, bool $bot ): void { |
||
154 | list( $newRevisionFrom, $newRevisionTo, $redirected ) |
||
155 | = $this->interactor->mergeItems( $fromId, $toId, $ignoreConflicts, $summary, $bot ); |
||
156 | |||
157 | $this->resultBuilder->setValue( null, 'success', 1 ); |
||
158 | $this->resultBuilder->setValue( null, 'redirected', (int)$redirected ); |
||
159 | |||
160 | $this->addEntityToOutput( $newRevisionFrom, 'from' ); |
||
161 | $this->addEntityToOutput( $newRevisionTo, 'to' ); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * @param Exception $ex |
||
166 | * @param string $errorCode |
||
167 | * @param string[] $extraData |
||
168 | * |
||
169 | * @throws ApiUsageException always |
||
170 | */ |
||
171 | private function handleException( Exception $ex, string $errorCode, array $extraData = [] ): void { |
||
172 | $cause = $ex->getPrevious(); |
||
173 | |||
174 | if ( $cause ) { |
||
175 | $extraData[] = $ex->getMessage(); |
||
176 | $this->handleException( $cause, $errorCode, $extraData ); |
||
177 | } else { |
||
178 | $this->errorReporter->dieException( $ex, $errorCode, 0, [ 'extradata' => $extraData ] ); |
||
179 | } |
||
180 | } |
||
181 | |||
182 | private function addEntityToOutput( EntityRevision $entityRevision, string $name ): void { |
||
183 | $entityId = $entityRevision->getEntity()->getId(); |
||
184 | $revisionId = $entityRevision->getRevisionId(); |
||
185 | |||
186 | $this->resultBuilder->addBasicEntityInformation( $entityId, $name ); |
||
0 ignored issues
–
show
It seems like
$entityId defined by $entityRevision->getEntity()->getId() on line 183 can be null ; however, Wikibase\Repo\Api\Result...asicEntityInformation() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
187 | |||
188 | $this->resultBuilder->setValue( |
||
189 | $name, |
||
190 | 'lastrevid', |
||
191 | (int)$revisionId |
||
192 | ); |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * @see ApiBase::needsToken |
||
197 | * |
||
198 | * @return string |
||
199 | */ |
||
200 | public function needsToken(): string { |
||
201 | return 'csrf'; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * @inheritDoc |
||
206 | */ |
||
207 | protected function getAllowedParams(): array { |
||
208 | return [ |
||
209 | 'fromid' => [ |
||
210 | self::PARAM_TYPE => 'string', |
||
211 | self::PARAM_REQUIRED => true, |
||
212 | ], |
||
213 | 'toid' => [ |
||
214 | self::PARAM_TYPE => 'string', |
||
215 | self::PARAM_REQUIRED => true, |
||
216 | ], |
||
217 | 'ignoreconflicts' => [ |
||
218 | self::PARAM_ISMULTI => true, |
||
219 | self::PARAM_TYPE => ChangeOpsMerge::$conflictTypes, |
||
220 | self::PARAM_REQUIRED => false, |
||
221 | ], |
||
222 | 'summary' => [ |
||
223 | self::PARAM_TYPE => 'string', |
||
224 | ], |
||
225 | 'bot' => [ |
||
226 | self::PARAM_TYPE => 'boolean', |
||
227 | self::PARAM_DFLT => false, |
||
228 | ], |
||
229 | 'token' => [ |
||
230 | self::PARAM_TYPE => 'string', |
||
231 | self::PARAM_REQUIRED => true, |
||
232 | ] |
||
233 | ]; |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * @inheritDoc |
||
238 | */ |
||
239 | protected function getExamplesMessages(): array { |
||
240 | return [ |
||
241 | 'action=wbmergeitems&fromid=Q42&toid=Q222' => |
||
242 | 'apihelp-wbmergeitems-example-1', |
||
243 | 'action=wbmergeitems&fromid=Q555&toid=Q3' => |
||
244 | 'apihelp-wbmergeitems-example-2', |
||
245 | 'action=wbmergeitems&fromid=Q66&toid=Q99&ignoreconflicts=sitelink' => |
||
246 | 'apihelp-wbmergeitems-example-3', |
||
247 | 'action=wbmergeitems&fromid=Q66&toid=Q99&ignoreconflicts=sitelink|description' => |
||
248 | 'apihelp-wbmergeitems-example-4', |
||
249 | ]; |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * @see ApiBase::isWriteMode |
||
254 | * |
||
255 | * @return bool Always true. |
||
256 | */ |
||
257 | public function isWriteMode(): bool { |
||
258 | return true; |
||
259 | } |
||
260 | |||
261 | } |
||
262 |
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.