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 namespace Arcanedev\Stripe; |
||
2 | |||
3 | use Arcanedev\Stripe\Contracts\StripeResource as StripeResourceContract; |
||
4 | use Arcanedev\Stripe\Http\RequestOptions; |
||
5 | use Arcanedev\Stripe\Http\Requestor; |
||
6 | use Arcanedev\Stripe\Utilities\Util; |
||
7 | use ReflectionClass; |
||
8 | |||
9 | /** |
||
10 | * Class StripeResource |
||
11 | * |
||
12 | * @package Arcanedev\Stripe |
||
13 | * @author ARCANEDEV <[email protected]> |
||
14 | */ |
||
15 | abstract class StripeResource extends StripeObject implements StripeResourceContract |
||
16 | { |
||
17 | /* ----------------------------------------------------------------- |
||
18 | | Properties |
||
19 | | ----------------------------------------------------------------- |
||
20 | */ |
||
21 | |||
22 | /** @var array */ |
||
23 | private static $persistedHeaders = [ |
||
24 | 'Stripe-Account' => true, |
||
25 | 'Stripe-Version' => true, |
||
26 | ]; |
||
27 | |||
28 | /* ----------------------------------------------------------------- |
||
29 | | Main Methods |
||
30 | | ----------------------------------------------------------------- |
||
31 | */ |
||
32 | |||
33 | /** |
||
34 | * Get the base url. |
||
35 | * |
||
36 | * @return string |
||
37 | */ |
||
38 | 396 | public static function baseUrl() |
|
39 | { |
||
40 | 396 | return Stripe::getApiBaseUrl(); |
|
41 | } |
||
42 | |||
43 | /** |
||
44 | * Get the refreshed resource. |
||
45 | * |
||
46 | * @return static |
||
47 | */ |
||
48 | 176 | public function refresh() |
|
49 | { |
||
50 | 176 | list($response, $this->opts->apiKey) = Requestor::make($this->opts->apiKey, self::baseUrl()) |
|
51 | 176 | ->get($this->instanceUrl(), $this->retrieveParameters, $this->opts->headers); |
|
52 | |||
53 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
54 | 150 | $this->setLastResponse($response); |
|
55 | 150 | $this->refreshFrom($response->getJson(), $this->opts); |
|
56 | |||
57 | 150 | return $this; |
|
58 | } |
||
59 | |||
60 | /** |
||
61 | * Get The name of the class, with namespacing and underscores stripped. |
||
62 | * |
||
63 | * @param string $class |
||
64 | * |
||
65 | * @return string |
||
66 | */ |
||
67 | 388 | public static function className($class = '') |
|
68 | { |
||
69 | 388 | $name = self::getShortNameClass($class); |
|
70 | 388 | $name = str_split_camelcase($name, '_'); |
|
71 | |||
72 | 388 | return strtolower(urlencode($name)); |
|
73 | } |
||
74 | |||
75 | /** |
||
76 | * Get Class short name. |
||
77 | * |
||
78 | * @param string $class |
||
79 | * |
||
80 | * @return string |
||
81 | */ |
||
82 | 388 | protected static function getShortNameClass($class = '') |
|
83 | { |
||
84 | 388 | if (empty($class)) |
|
85 | 380 | $class = get_called_class(); |
|
86 | |||
87 | 388 | return (new ReflectionClass($class))->getShortName(); |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * Get the endpoint URL for the given class. |
||
92 | * |
||
93 | * @param string $class |
||
94 | * |
||
95 | * @return string |
||
96 | */ |
||
97 | 382 | public static function classUrl($class = '') |
|
98 | { |
||
99 | 382 | $base = self::className($class); |
|
100 | |||
101 | 382 | return "/v1/${base}s"; |
|
102 | } |
||
103 | |||
104 | /** |
||
105 | * Get Instance URL. |
||
106 | * |
||
107 | * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException |
||
108 | * |
||
109 | * @return string |
||
110 | */ |
||
111 | public function instanceUrl() |
||
112 | { |
||
113 | 234 | return static::resourceUrl($this['id']); |
|
114 | } |
||
115 | |||
116 | /** |
||
117 | * Get the instance endpoint URL for the given class. |
||
118 | * |
||
119 | * @param string $id |
||
120 | * |
||
121 | * @return string |
||
122 | * |
||
123 | * @throws Exceptions\InvalidRequestException |
||
124 | */ |
||
125 | public static function resourceUrl($id) |
||
126 | { |
||
127 | 284 | if ($id === null) { |
|
128 | 6 | $class = get_called_class(); |
|
129 | 6 | throw new Exceptions\InvalidRequestException( |
|
130 | 6 | "Could not determine which URL to request: $class instance has invalid ID: $id", null |
|
131 | ); |
||
132 | } |
||
133 | |||
134 | 278 | return static::classUrl().'/'.urlencode(str_utf8($id)); |
|
135 | } |
||
136 | |||
137 | /* ------------------------------------------------------------------------------------------------ |
||
138 | | Request Functions |
||
139 | | ------------------------------------------------------------------------------------------------ |
||
140 | */ |
||
141 | /** |
||
142 | * Make a request. |
||
143 | * |
||
144 | * @param string $method |
||
145 | * @param string $url |
||
146 | * @param array|null $params |
||
147 | * @param array|string|null $options |
||
148 | * |
||
149 | * @return array |
||
150 | */ |
||
151 | protected function request($method, $url, $params = [], $options = null) |
||
152 | { |
||
153 | 144 | $opts = $this->opts->merge($options); |
|
154 | |||
155 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
156 | 144 | list($response, $options) = static::staticRequest($method, $url, $params, $opts); |
|
157 | 144 | $this->setLastResponse($response); |
|
158 | |||
159 | 144 | return [$response->getJson(), $options]; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * Make a request (static). |
||
164 | * |
||
165 | * @param string $method |
||
166 | * @param string $url |
||
167 | * @param array|null $params |
||
168 | * @param array|string|null $options |
||
169 | * |
||
170 | * @return array |
||
171 | */ |
||
172 | protected static function staticRequest($method, $url, $params, $options) |
||
173 | { |
||
174 | 374 | $opts = RequestOptions::parse($options); |
|
175 | 374 | $requestor = Requestor::make($opts->apiKey, static::baseUrl()); |
|
176 | |||
177 | 362 | list($response, $opts->apiKey) = |
|
178 | 374 | $requestor->request($method, $url, $params, $opts->headers); |
|
179 | |||
180 | 362 | foreach ($opts->headers as $k => $v) { |
|
181 | 26 | if ( ! array_key_exists($k, self::$persistedHeaders)) |
|
182 | 26 | unset($opts->headers[$k]); |
|
183 | } |
||
184 | |||
185 | 362 | return [$response, $opts]; |
|
186 | } |
||
187 | |||
188 | /* ----------------------------------------------------------------- |
||
189 | | CRUD Scope Methods |
||
190 | | ----------------------------------------------------------------- |
||
191 | */ |
||
192 | |||
193 | /** |
||
194 | * Retrieve scope. |
||
195 | * |
||
196 | * @param string $id |
||
197 | * @param array|string|null $options |
||
198 | * |
||
199 | * @return static |
||
200 | */ |
||
201 | protected static function scopedRetrieve($id, $options = null) |
||
202 | { |
||
203 | 172 | $class = get_called_class(); |
|
204 | |||
205 | /** @var self $resource */ |
||
206 | 172 | $resource = new $class($id, RequestOptions::parse($options)); |
|
207 | 172 | $resource->refresh(); |
|
208 | |||
209 | 146 | return $resource; |
|
210 | } |
||
211 | |||
212 | /** |
||
213 | * List scope. |
||
214 | * |
||
215 | * @param array|null $params |
||
216 | * @param array|string|null $options |
||
217 | * |
||
218 | * @throws \Arcanedev\Stripe\Exceptions\ApiException |
||
219 | * |
||
220 | * @return \Arcanedev\Stripe\Collection|array |
||
221 | */ |
||
222 | protected static function scopedAll($params = [], $options = null) |
||
223 | { |
||
224 | 60 | self::checkArguments($params, $options); |
|
225 | |||
226 | 56 | $url = static::classUrl(); |
|
227 | |||
228 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
229 | 56 | list($response, $opts) = self::staticRequest('get', $url, $params, $options); |
|
230 | |||
231 | 56 | $object = Util::convertToStripeObject($response->getJson(), $opts); |
|
232 | |||
233 | 56 | self::checkIsCollectionObject($object); |
|
234 | |||
235 | 56 | $object->setLastResponse($response); |
|
236 | 56 | $object->setRequestParams($params); |
|
0 ignored issues
–
show
|
|||
237 | |||
238 | 56 | return $object; |
|
239 | } |
||
240 | |||
241 | /** |
||
242 | * Create scope. |
||
243 | * |
||
244 | * @param array|null $params |
||
245 | * @param array|string|null $options |
||
246 | * |
||
247 | * @throws \Arcanedev\Stripe\Exceptions\ApiException |
||
248 | * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException |
||
249 | * |
||
250 | * @return static |
||
251 | */ |
||
252 | protected static function scopedCreate($params = [], $options = null) |
||
253 | { |
||
254 | 276 | self::checkArguments($params, $options); |
|
255 | |||
256 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
257 | 276 | list($response, $opts) = static::staticRequest('post', static::classUrl(), $params, $options); |
|
258 | |||
259 | 264 | $object = Util::convertToStripeObject($response->getJson(), $opts); |
|
0 ignored issues
–
show
The expression
\Arcanedev\Stripe\Utilit...nse->getJson(), $opts); of type Arcanedev\Stripe\StripeO...Stripe\Collection|array adds the type array to the return on line 262 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedCreate of type Arcanedev\Stripe\StripeResource .
![]() |
|||
260 | 264 | $object->setLastResponse($response); |
|
261 | |||
262 | 264 | return $object; |
|
263 | } |
||
264 | |||
265 | /** |
||
266 | * Update scope. |
||
267 | * |
||
268 | * @param string $id |
||
269 | * @param array|null $params |
||
270 | * @param array|string|null $options |
||
271 | * |
||
272 | * @return static |
||
273 | * |
||
274 | * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException |
||
275 | */ |
||
276 | protected static function scopedUpdate($id, $params = null, $options = null) |
||
277 | { |
||
278 | 32 | self::checkArguments($params, $options); |
|
279 | |||
280 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
281 | 32 | list($response, $opts) = static::staticRequest('post', static::resourceUrl($id), $params, $options); |
|
282 | |||
283 | 32 | $object = Util::convertToStripeObject($response->getJson(), $opts); |
|
0 ignored issues
–
show
It seems like
$response->getJson() targeting Arcanedev\Stripe\Http\Response::getJson() can also be of type null ; however, Arcanedev\Stripe\Utiliti...convertToStripeObject() does only seem to accept array , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() The expression
\Arcanedev\Stripe\Utilit...nse->getJson(), $opts); of type Arcanedev\Stripe\StripeO...Stripe\Collection|array adds the type array to the return on line 286 which is incompatible with the return type documented by Arcanedev\Stripe\StripeResource::scopedUpdate of type Arcanedev\Stripe\StripeResource .
![]() |
|||
284 | 32 | $object->setLastResponse($response); |
|
285 | |||
286 | 32 | return $object; |
|
287 | } |
||
288 | |||
289 | /** |
||
290 | * Save scope. |
||
291 | * |
||
292 | * @param array|string|null $options |
||
293 | * |
||
294 | * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException |
||
295 | * |
||
296 | * @return static |
||
297 | */ |
||
298 | protected function scopedSave($options = null) |
||
299 | { |
||
300 | 88 | if (count($params = $this->serializeParameters()) > 0) { |
|
301 | 72 | self::checkArguments(null, $options); |
|
302 | 72 | list($response, $opts) = $this->request('post', $this->instanceUrl(), $params, $options); |
|
303 | 72 | $this->refreshFrom($response, $opts); |
|
304 | } |
||
305 | |||
306 | 88 | return $this; |
|
307 | } |
||
308 | |||
309 | /** |
||
310 | * Delete Scope. |
||
311 | * |
||
312 | * @param array|null $params |
||
313 | * @param array|string|null $options |
||
314 | * |
||
315 | * @throws \Arcanedev\Stripe\Exceptions\InvalidRequestException |
||
316 | * |
||
317 | * @return static |
||
318 | */ |
||
319 | protected function scopedDelete($params = [], $options = null) |
||
320 | { |
||
321 | 32 | self::checkArguments($params, $options); |
|
322 | |||
323 | 32 | list($response, $opts) = $this->request('delete', $this->instanceUrl(), $params, $options); |
|
324 | 32 | $this->refreshFrom($response, $opts); |
|
325 | |||
326 | 32 | return $this; |
|
327 | } |
||
328 | |||
329 | /* ----------------------------------------------------------------- |
||
330 | | Nested Resources Methods |
||
331 | | ----------------------------------------------------------------- |
||
332 | */ |
||
333 | |||
334 | /** |
||
335 | * Create a nested resource. |
||
336 | * |
||
337 | * @param string $id |
||
338 | * @param string $nestedPath |
||
339 | * @param array|null $params |
||
340 | * @param array|string|null $options |
||
341 | * |
||
342 | * @return mixed |
||
343 | */ |
||
344 | protected static function createNestedResource($id, $nestedPath, $params = null, $options = null) |
||
345 | { |
||
346 | 10 | $url = static::nestedResourceUrl($id, $nestedPath); |
|
347 | |||
348 | 10 | return static::nestedResourceRequest('post', $url, $params, $options); |
|
349 | } |
||
350 | |||
351 | /** |
||
352 | * Retrieve a nested resource. |
||
353 | * |
||
354 | * @param string $id |
||
355 | * @param string $nestedPath |
||
356 | * @param string $nestedId |
||
357 | * @param array|null $params |
||
358 | * @param array|string|null $options |
||
359 | * |
||
360 | * @return mixed |
||
361 | */ |
||
362 | protected static function retrieveNestedResource($id, $nestedPath, $nestedId, $params = null, $options = null) |
||
363 | { |
||
364 | 8 | $url = static::nestedResourceUrl($id, $nestedPath, $nestedId); |
|
365 | |||
366 | 8 | return static::nestedResourceRequest('get', $url, $params, $options); |
|
367 | } |
||
368 | |||
369 | /** |
||
370 | * Update a nested resource. |
||
371 | * |
||
372 | * @param string $id |
||
373 | * @param string $nestedPath |
||
374 | * @param array|null $params |
||
375 | * @param array|string|null $options |
||
376 | * |
||
377 | * @return mixed |
||
378 | */ |
||
379 | protected static function updateNestedResource($id, $nestedPath, $nestedId, $params = null, $options = null) |
||
380 | { |
||
381 | 8 | $url = static::nestedResourceUrl($id, $nestedPath, $nestedId); |
|
382 | |||
383 | 8 | return static::nestedResourceRequest('post', $url, $params, $options); |
|
384 | } |
||
385 | |||
386 | /** |
||
387 | * Delete a nested resource. |
||
388 | * |
||
389 | * @param string $id |
||
390 | * @param string $nestedPath |
||
391 | * @param string $nestedId |
||
392 | * @param array|null $params |
||
393 | * @param array|string|null $options |
||
394 | * |
||
395 | * @return mixed |
||
396 | */ |
||
397 | protected static function deleteNestedResource($id, $nestedPath, $nestedId, $params = null, $options = null) |
||
398 | { |
||
399 | 4 | $url = static::nestedResourceUrl($id, $nestedPath, $nestedId); |
|
400 | |||
401 | 4 | return static::nestedResourceRequest('delete', $url, $params, $options); |
|
402 | } |
||
403 | |||
404 | /** |
||
405 | * Get all the nested resources. |
||
406 | * |
||
407 | * @param string $id |
||
408 | * @param string $nestedPath |
||
409 | * @param array|null $params |
||
410 | * @param array|string|null $options |
||
411 | * |
||
412 | * @return \Arcanedev\Stripe\Collection |
||
413 | */ |
||
414 | protected static function allNestedResources($id, $nestedPath, $params = null, $options = null) |
||
415 | { |
||
416 | 8 | $url = static::nestedResourceUrl($id, $nestedPath); |
|
417 | |||
418 | 8 | return static::nestedResourceRequest('get', $url, $params, $options); |
|
419 | } |
||
420 | |||
421 | /** |
||
422 | * Make a request call to a nested nested resource. |
||
423 | * |
||
424 | * @param string $method |
||
425 | * @param string $url |
||
426 | * @param array|null $params |
||
427 | * @param array|string|null $options |
||
428 | * |
||
429 | * @return mixed |
||
430 | */ |
||
431 | protected static function nestedResourceRequest($method, $url, $params = null, $options = null) |
||
432 | { |
||
433 | 38 | static::checkParameters($params); |
|
0 ignored issues
–
show
Since
checkParameters() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self , or increase the visibility of checkParameters() to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return static::getTemperature();
}
} The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass {
private static function getTemperature() {
return "-182 °C";
}
}
print YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class YourClass
{
private static function getTemperature() {
return "3422 °C";
}
public static function getSomeVariable()
{
return self::getTemperature();
}
}
![]() |
|||
434 | |||
435 | 38 | list($response, $opts) = static::staticRequest($method, $url, $params, $options); |
|
436 | |||
437 | 38 | return Utilities\Util::convertToStripeObject($response->getJson(), $opts) |
|
438 | 38 | ->setLastResponse($response); |
|
439 | } |
||
440 | |||
441 | /** |
||
442 | * Prepare the nested resource URL. |
||
443 | * |
||
444 | * @param string $id |
||
445 | * @param string $nestedPath |
||
446 | * @param string|null $nestedId |
||
447 | * |
||
448 | * @return string |
||
449 | */ |
||
450 | protected static function nestedResourceUrl($id, $nestedPath, $nestedId = null) |
||
451 | { |
||
452 | 38 | $url = static::resourceUrl($id).$nestedPath; |
|
453 | |||
454 | 38 | return is_null($nestedId) ? $url : "$url/$nestedId"; |
|
455 | } |
||
456 | |||
457 | /* ----------------------------------------------------------------- |
||
458 | | Custom Scope Methods |
||
459 | | ----------------------------------------------------------------- |
||
460 | */ |
||
461 | |||
462 | /** |
||
463 | * Custom Post Call. |
||
464 | * |
||
465 | * @param string $url |
||
466 | * @param array|null $params |
||
467 | * @param array|string|null $options |
||
468 | * |
||
469 | * @return static |
||
470 | */ |
||
471 | protected function scopedPostCall($url, $params = [], $options = null) |
||
472 | { |
||
473 | /** @var \Arcanedev\Stripe\Http\Response $response */ |
||
474 | 18 | list($response, $options) = Requestor::make(RequestOptions::parse($options)->getApiKey(), static::baseUrl()) |
|
475 | 18 | ->post($url, $params); |
|
476 | |||
477 | 18 | $this->refreshFrom($response->getJson(), $options); |
|
478 | 18 | $this->setLastResponse($response); |
|
479 | |||
480 | 18 | return $this; |
|
481 | } |
||
482 | |||
483 | /* ----------------------------------------------------------------- |
||
484 | | Check Methods |
||
485 | | ----------------------------------------------------------------- |
||
486 | */ |
||
487 | |||
488 | /** |
||
489 | * Check Arguments. |
||
490 | * |
||
491 | * @param array|null $params |
||
492 | * @param array|string|null $options |
||
493 | */ |
||
494 | protected static function checkArguments($params = [], $options = null) |
||
495 | { |
||
496 | 330 | self::checkParameters($params); |
|
497 | 328 | self::checkOptions($options); |
|
498 | 326 | } |
|
499 | |||
500 | /** |
||
501 | * Check parameters. |
||
502 | * |
||
503 | * @param array|null $params |
||
504 | * |
||
505 | * @throws \Arcanedev\Stripe\Exceptions\InvalidArgumentException |
||
506 | */ |
||
507 | private static function checkParameters($params) |
||
508 | { |
||
509 | 368 | if ($params && ! is_array($params)) { |
|
510 | 2 | throw new Exceptions\InvalidArgumentException( |
|
511 | 'You must pass an array as the first argument to Stripe API method calls. '. |
||
512 | '(HINT: an example call to create a charge would be: '. |
||
513 | 2 | "StripeCharge::create(['amount' => 100, 'currency' => 'usd', 'source' => 'tok_1234']))" |
|
514 | ); |
||
515 | } |
||
516 | 366 | } |
|
517 | |||
518 | /** |
||
519 | * Check Options. |
||
520 | * |
||
521 | * @param array|string|null $options |
||
522 | * |
||
523 | * @throws \Arcanedev\Stripe\Exceptions\ApiException |
||
524 | */ |
||
525 | private static function checkOptions($options) |
||
526 | { |
||
527 | 328 | if ($options && ( |
|
528 | 36 | ! $options instanceof RequestOptions && |
|
529 | 36 | ! is_string($options) && |
|
530 | 328 | ! is_array($options) |
|
531 | ) |
||
532 | ) { |
||
533 | 2 | throw new Exceptions\ApiException( |
|
534 | 'The second argument to Stripe API method calls is an ' |
||
535 | . 'optional per-request apiKey, which must be a string. ' |
||
536 | 2 | . '(HINT: you can set a global apiKey by "Stripe::setApiKey(<apiKey>)")', |
|
537 | 2 | 500 |
|
538 | ); |
||
539 | } |
||
540 | 326 | } |
|
541 | |||
542 | /** |
||
543 | * Check the object is a Collection class. |
||
544 | * |
||
545 | * @param mixed $object |
||
546 | * |
||
547 | * @throws \Arcanedev\Stripe\Exceptions\ApiException |
||
548 | */ |
||
549 | private static function checkIsCollectionObject($object) |
||
550 | { |
||
551 | 56 | if ( ! is_a($object, Collection::class)) { |
|
552 | throw new Exceptions\ApiException( |
||
553 | 'Expected type "Arcanedev\Stripe\Collection", got "'.get_class($object).'" instead' |
||
554 | ); |
||
555 | } |
||
556 | 56 | } |
|
557 | } |
||
558 |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: