Issues (40)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Objects/ApiObject.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @copyright 2017 Vladimir Jimenez
5
 * @license   https://github.com/allejo/PhpPulse/blob/master/LICENSE.md MIT
6
 */
7
8
namespace allejo\DaPulse\Objects;
9
10
use allejo\DaPulse\Exceptions\InvalidObjectException;
11
use allejo\DaPulse\Utilities\UrlQuery;
12
13
/**
14
 * The base class for all DaPulse API objects
15
 *
16
 * @internal
17
 * @package allejo\DaPulse\Objects
18
 * @since   0.1.0
19
 */
20
abstract class ApiObject implements \JsonSerializable
21
{
22
    /**
23
     * The namespace used for all main PhpPulse objects. This is value is prepended before PhpPulse objects when being
24
     * checked with `instanceof`.
25
     *
26
     * @internal
27
     */
28
    const OBJ_NAMESPACE = "\\allejo\\DaPulse\\";
29
30
    /**
31
     * The default API protocol used for URL calls
32
     *
33
     * @internal
34
     */
35
    const API_PROTOCOL = "https";
36
37
    /**
38
     * The API end point for URL calls
39
     *
40
     * @internal
41
     */
42
    const API_ENDPOINT = "api.monday.com";
43
44
    /**
45
     * The API version used for URL calls
46
     *
47
     * @internal
48
     */
49
    const API_VERSION = "v1";
50
51
    /**
52
     * The suffix that is appended to the URL to access functionality for certain objects
53
     *
54
     * @internal
55
     */
56
    const API_PREFIX = "";
57
58
    /**
59
     * The API key used to make the URL calls
60
     *
61
     * @var string
62
     */
63
    protected static $apiKey;
64
65
    /**
66
     * When set to true, the object can only be constructed from an associative array of data. It will not attempt
67
     * to fetch the data with an API call; this is intended for objects are not directly accessible via the API.
68
     *
69
     * @var bool
70
     */
71
    protected $arrayConstructionOnly = false;
72
73
    /**
74
     * Set to true if the object has been deleted via an API call but the instance still exists. This variable will
75
     * prevent further API calls to a nonexistent object.
76
     *
77
     * @var bool
78
     */
79
    protected $deletedObject = false;
80
81
    /**
82
     * An associative array representing the original JSON response from DaPulse
83
     *
84
     * @var array
85
     */
86
    protected $jsonResponse;
87
88
    protected $urlEndPoint;
89
90
    /**
91
     * The ID for the object we're handling
92
     *
93
     * @var int
94
     */
95
    protected $id;
96
97
    /**
98
     * Create an object from an API call
99
     *
100
     * @param int|array $idOrArray Either the numerical ID of an object or an associative array representing a JSON
101
     *                             response from an API call
102
     * @param bool      $lazyLoad  When set to true, an initial API call will not be made. An API call will be made when
103
     *                             the information is requested
104
     *
105
     * @throws \InvalidArgumentException The specified object cannot be created directly from an API call but instead
106
     *                                   requires an associative array of information gathered from other API calls.
107
     *
108
     * @since 0.1.0
109
     */
110 115
    public function __construct ($idOrArray, $lazyLoad = false)
111
    {
112 115
        $staticClass = explode("\\", get_called_class());
113 115
        $staticClass = end($staticClass);
114
115 115
        if (is_null($idOrArray))
116
        {
117
            throw new \InvalidArgumentException("You may not initialize $staticClass with null.");
118
        }
119
120 115
        if (!is_array($idOrArray))
121
        {
122 115
            $this->urlEndPoint = sprintf("%s/%d.json", self::apiEndpoint(), $idOrArray);
123
        }
124
125 115
        if ($this->arrayConstructionOnly && !is_array($idOrArray))
126
        {
127
            throw new \InvalidArgumentException("A $staticClass cannot be fetched from an ID.");
128
        }
129
130 115
        $this->initializeValues();
131
132 115
        if (is_array($idOrArray))
133
        {
134 97
            $this->jsonResponse = $idOrArray;
135 97
            $this->assignResults();
136
        }
137
        else
138
        {
139 115
            if ($lazyLoad)
140
            {
141 17
                $this->id           = $idOrArray;
142 17
                $this->jsonResponse = [];
143
            }
144
            else
145
            {
146 111
                $this->lazyLoad();
147
            }
148
        }
149 115
    }
150
151
    /**
152
     * Access the JSON response from DaPulse used to create this wrapper object
153
     *
154
     * If a wrapper getter function isn't available for a certain value, use this function to access the value directly.
155
     *
156
     * @api
157
     * @since 0.2.0
158
     * @return mixed
159
     */
160
    public function jsonSerialize ()
161
    {
162
        return $this->jsonResponse;
163
    }
164
165 111
    protected function lazyLoad ()
166
    {
167 111
        if (empty($this->jsonResponse))
168
        {
169 111
            $this->jsonResponse = $this->sendGet($this->urlEndPoint);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->sendGet($this->urlEndPoint) of type * is incompatible with the declared type array of property $jsonResponse.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
170 111
            $this->assignResults();
171
        }
172 111
    }
173
174
    // ================================================================================================================
175
    //   Helper functions
176
    // ================================================================================================================
177
178
    /**
179
     * Assign an associative array from a JSON response and map them to instance variables
180
     *
181
     * @since 0.1.0
182
     */
183 113
    final protected function assignResults ()
184
    {
185 113
        foreach ($this->jsonResponse as $key => $val)
186
        {
187 113
            if (property_exists(get_called_class(), $key))
188
            {
189 113
                $this->$key = $val;
190
            }
191
        }
192 113
    }
193
194
    /**
195
     * Check if the current object has been marked as deleted from DaPulse. If so, throw an exception.
196
     *
197
     * @throws InvalidObjectException
198
     */
199 4
    final protected function checkInvalid ()
200
    {
201 4
        if ($this->deletedObject)
202
        {
203 2
            throw new InvalidObjectException("This object no longer exists on DaPulse", 2);
204
        }
205 4
    }
206
207
    /**
208
     * Mark an object as deleted
209
     *
210
     * @internal
211
     */
212
    final public function _markInvalid ()
213
    {
214
        $this->deletedObject = true;
215
    }
216
217
    /**
218
     * Store the value in an array if the value is not null. This function is a shortcut of setting values in an array
219
     * only if they are not null, if not leave them unset; used ideally for PUT requests.
220
     *
221
     * @param array  $array The array that will store all of the POST parameters
222
     * @param string $name  The name of the field
223
     * @param mixed  $value The value to be stored in a given field
224
     */
225 45
    final protected static function setIfNotNullOrEmpty (&$array, $name, $value)
226
    {
227 45
        if (!is_null($value) && !empty($value))
228
        {
229 40
            $array[$name] = $value;
230
        }
231 45
    }
232
233
    // ================================================================================================================
234
    //   Empty functions
235
    // ================================================================================================================
236
237
    /**
238
     * Overload this function if any class variables need to be initialized to a default value
239
     */
240 102
    protected function initializeValues ()
241
    {
242 102
    }
243
244
    // ================================================================================================================
245
    //   Lazy loading functions
246
    // ================================================================================================================
247
248
    /**
249
     * Inject data into the array that will be mapped into individual instance variables. This function must be called
250
     * **before** lazyCastAll() is called and maps the associative array to objects.
251
     *
252
     * @param array $target An array of associative arrays with data to be converted into objects
253
     * @param array $array  An associative array containing data to be merged with the key being the name of the
254
     *                      instance variable.
255
     *
256
     * @throws \InvalidArgumentException If either parameters are not arrays
257
     *
258
     * @since 0.1.0
259
     */
260 40
    final protected static function lazyInject (&$target, $array)
261
    {
262 40
        if (!is_array($target) || !is_array($array))
263
        {
264
            throw new \InvalidArgumentException("Both the target and array must be arrays");
265
        }
266
267
        // If the first element is an array, let's assume $target hasn't been lazily casted into objects
268 40
        if (is_array($target[0]))
269
        {
270 40
            foreach ($target as &$element)
271
            {
272 40
                $element = array_merge($element, $array);
273
            }
274
        }
275 40
    }
276
277
    /**
278
     * Convert the specified array into an array of object types if needed
279
     *
280
     * @param  array  $array      The array to check
281
     * @param  string $objectType The class name of the Objects the items should be
282
     * @param  bool   $lazyLoad   Should the casted objects be created lazily
283
     *
284
     * @since  0.2.0
285
     */
286 49
    final protected static function lazyCastAll (&$array, $objectType, $lazyLoad = false)
287
    {
288 49
        if (self::lazyCastNeededOnArray($objectType, $array))
289
        {
290 45
            $array = self::castArrayToObjectArray($objectType, $array, $lazyLoad);
291
        }
292 49
    }
293
294
    /**
295
     * Convert the specified item into the specified object if needed
296
     *
297
     * @param mixed  $target     The item to check
298
     * @param string $objectType The class name of the Objects the items should be
299
     *
300
     * @since 0.2.0
301
     */
302 11
    final protected static function lazyCast (&$target, $objectType)
303
    {
304 11
        if (self::lazyCastNeeded($target, $objectType))
305
        {
306 11
            $object = ($objectType[0] == "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
307 11
            $target = new $object($target);
308
        }
309 11
    }
310
311
    /**
312
     * Check whether it is required for an array of JSON data to be converted into an array of the specified objects
313
     *
314
     * @param  string $objectType The class name of the Objects the items should be
315
     * @param  array  $array      The array to check
316
     *
317
     * @since  0.2.0
318
     *
319
     * @return bool True if the array needs to converted into an array of objects
320
     */
321 49
    final protected static function lazyCastNeededOnArray ($objectType, $array)
322
    {
323 49
        if (is_array($array) && count($array) == 0)
324
        {
325 1
            return false;
326
        }
327
328 48
        $firstItem = $array[0];
329
330 48
        return self::lazyCastNeeded($firstItem, $objectType);
331
    }
332
333
    /**
334
     * Check if an individual item needs to be lazily converted into an object
335
     *
336
     * @param  mixed  $target     The item to check
337
     * @param  string $objectType The class name of the Objects the items should be
338
     *
339
     * @since  0.2.0
340
     *
341
     * @return bool
342
     */
343 57
    final protected static function lazyCastNeeded ($target, $objectType)
344
    {
345 57
        $objectDefinition = ($objectType[0] === "\\") ? $objectType : self::OBJ_NAMESPACE . $objectType;
346
347 57
        return !($target instanceof $objectDefinition);
348
    }
349
350
    /**
351
     * Sends a GET request for a JSON array and casts the response into an array of objects
352
     *
353
     * @param  string $url       The API endpoint to call to get the JSON response from
354
     * @param  string $className The class name of the Object type to cast to
355
     * @param  array  $params    An associative array of URL parameters that will be passed to the specific call. For
356
     *                           example, limiting the number of results or the pagination of results. **Warning** The
357
     *                           API key does NOT need to be passed here
358
     *
359
     * @since  0.2.0
360
     *
361
     * @return array
362
     */
363 28
    final protected static function fetchAndCastToObjectArray ($url, $className, $params = [])
364
    {
365 28
        $objects = self::sendGet($url, $params);
366
367 28
        return self::castArrayToObjectArray($className, $objects);
368
    }
369
370
    /**
371
     * Convert an array of associative arrays into a specific object
372
     *
373
     * @param  string $className The class name of the Object type
374
     * @param  array  $objects   An associative array to be converted into an object
375
     * @param  bool   $lazyLoad  Should the casted objects be created lazily
376
     *
377
     * @since  0.2.0
378
     *
379
     * @return array An array of the specified objects
380
     */
381 68
    final protected static function castArrayToObjectArray ($className, $objects, $lazyLoad = false)
382
    {
383 68
        $class = self::OBJ_NAMESPACE . $className;
384 68
        $array = [];
385
386 68
        foreach ($objects as $post)
387
        {
388 68
            $array[] = new $class($post, $lazyLoad);
389
        }
390
391 68
        return $array;
392
    }
393
394
    // ================================================================================================================
395
    //   URL jobs functions
396
    // ================================================================================================================
397
398
    /**
399
     * Send a GET request to fetch the data from the specified URL
400
     *
401
     * @param  string $url    The API endpoint to call
402
     * @param  array  $params An associative array of URL parameters that will be passed to the specific call. For
403
     *                        example, limiting the number of results or the pagination of results. **Warning** The API
404
     *                        key does NOT need to be passed here
405
     *
406
     * @since  0.1.0
407
     *
408
     * @return mixed          An associative array of the JSON response from DaPulse
409
     */
410 111
    final protected static function sendGet ($url, $params = [])
411
    {
412 111
        $params["api_key"] = self::$apiKey;
413
414 111
        $urlQuery = new UrlQuery($url, $params);
415
416 111
        return $urlQuery->sendGet();
417
    }
418
419
    /**
420
     * Send a POST request to a specified URL
421
     *
422
     * @param  string $url
423
     * @param  array  $postParams
424
     * @param  array  $getParams
425
     *
426
     * @since  0.1.0
427
     *
428
     * @return mixed
429
     */
430 9
    final protected static function sendPost ($url, $postParams, $getParams = [])
431
    {
432 9
        return self::sendRequest("POST", $url, $postParams, $getParams);
433
    }
434
435
    /**
436
     * Send a PUT request to a specified URL
437
     *
438
     * @param  string $url
439
     * @param  array  $postParams
440
     * @param  array  $getParams
441
     *
442
     * @since  0.1.0
443
     *
444
     * @return mixed
445
     */
446 11
    final protected static function sendPut ($url, $postParams, $getParams = [])
447
    {
448 11
        return self::sendRequest("PUT", $url, $postParams, $getParams);
449
    }
450
451
    /**
452
     * Send a DELETE request to a specified URL
453
     *
454
     * @param  string $url
455
     * @param  array  $getParams
456
     *
457
     * @since  0.1.0
458
     *
459
     * @return mixed
460
     */
461 6
    final protected static function sendDelete ($url, $getParams = [])
462
    {
463 6
        return self::sendRequest("DELETE", $url, null, $getParams);
0 ignored issues
show
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
464
    }
465
466
    /**
467
     * Send the appropriate URL request
468
     *
469
     * @param  string $type
470
     * @param  string $url
471
     * @param  array  $postParams
472
     * @param  array  $getParams
473
     *
474
     * @throws \InvalidArgumentException if $type not 'POST', 'PUT', or 'DELETE'
475
     *
476
     * @since  0.1.0
477
     *
478
     * @return mixed
479
     */
480 26
    private static function sendRequest ($type, $url, $postParams, $getParams)
481
    {
482 26
        $getParams["api_key"] = self::$apiKey;
483
484 26
        $urlQuery = new UrlQuery($url, $getParams);
485
486
        switch ($type)
487
        {
488 26
            case "POST":
489 9
                return $urlQuery->sendPost($postParams);
490
491 17
            case "PUT":
492 11
                return $urlQuery->sendPut($postParams);
493
494 6
            case "DELETE":
495 6
                return $urlQuery->sendDelete();
496
497
            default:
498
                throw new \InvalidArgumentException();
499
        }
500
    }
501
502
    // ================================================================================================================
503
    //   API key functions
504
    // ================================================================================================================
505
506
    /**
507
     * Get the base URL to use in all of the API calls
508
     *
509
     * @param  string|null $apiPrefix If the API end point is different from the class's constant, this value will be
510
     *                                used as the suffix for the API endpoint
511
     *
512
     * @since  0.1.0
513
     *
514
     * @return string The base URL to call
515
     */
516 115
    final protected static function apiEndpoint ($apiPrefix = null)
517
    {
518 115
        $apiSection = isset($apiPrefix) ? $apiPrefix : static::API_PREFIX;
519
520 115
        return sprintf("%s://%s/%s/%s", self::API_PROTOCOL, self::API_ENDPOINT, self::API_VERSION, $apiSection);
521
    }
522
523
    /**
524
     * Set the API for all calls to the API
525
     *
526
     * @param string $apiKey The API key used to access the DaPulse API
527
     *
528
     * @since 0.1.0
529
     */
530
    final public static function setApiKey ($apiKey)
531
    {
532
        self::$apiKey = $apiKey;
533
    }
534
}
535