tmhOAuth   F
last analyzed

Complexity

Total Complexity 84

Size/Duplication

Total Lines 665
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 665
rs 1.935
c 0
b 0
f 0
wmc 84
lcom 1
cbo 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 67 1
A set_user_agent() 0 13 4
A create_nonce() 0 10 4
A create_timestamp() 0 3 2
A safe_encode() 0 13 3
A safe_decode() 0 9 3
A get_defaults() 0 20 3
A extract_params() 0 11 2
A prepare_method() 0 3 1
B prepare_url() 0 20 9
B prepare_params() 0 47 7
A prepare_signing_key() 0 3 1
A prepare_base_string() 0 8 1
A prepare_auth_header() 0 14 3
A sign() 0 19 2
A request() 0 13 2
A streaming_request() 0 16 3
A update_metrics() 0 13 2
A url() 0 20 5
A transformText() 0 3 1
A curlHeader() 0 8 1
A curlWrite() 0 29 4
F curlit() 0 116 20

How to fix   Complexity   

Complex Class

Complex classes like tmhOAuth often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use tmhOAuth, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * tmhOAuth
4
 *
5
 * An OAuth 1.0A library written in PHP.
6
 * The library supports file uploading using multipart/form as well as general
7
 * REST requests. OAuth authentication is sent using the an Authorization Header.
8
 *
9
 * @author themattharris
10
 * @version 0.7.2
11
 *
12
 * 01 November 2012
13
 */
14
class tmhOAuth {
15
  const VERSION = '0.7.2';
16
17
  var $response = array();
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $response.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
18
19
  /**
20
   * Creates a new tmhOAuth object
21
   *
22
   * @param string $config, the configuration to use for this request
0 ignored issues
show
Documentation introduced by
There is no parameter named $config,. Did you maybe mean $config?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
23
   */
24
  public function __construct($config=array()) {
25
    $this->params = array();
26
    $this->headers = array();
27
    $this->auto_fixed_time = false;
28
    $this->buffer = null;
29
30
    // default configuration options
31
    $this->config = array_merge(
32
      array(
33
        // leave 'user_agent' blank for default, otherwise set this to
34
        // something that clearly identifies your app
35
        'user_agent'                 => '',
36
        // default timezone for requests
37
        'timezone'                   => 'UTC',
38
39
        'use_ssl'                    => true,
40
        'host'                       => 'api.twitter.com',
41
42
        'consumer_key'               => '',
43
        'consumer_secret'            => '',
44
        'user_token'                 => '',
45
        'user_secret'                => '',
46
        'force_nonce'                => false,
47
        'nonce'                      => false, // used for checking signatures. leave as false for auto
48
        'force_timestamp'            => false,
49
        'timestamp'                  => false, // used for checking signatures. leave as false for auto
50
51
        // oauth signing variables that are not dynamic
52
        'oauth_version'              => '1.0',
53
        'oauth_signature_method'     => 'HMAC-SHA1',
54
55
        // you probably don't want to change any of these curl values
56
        'curl_connecttimeout'        => 30,
57
        'curl_timeout'               => 10,
58
59
        // for security this should always be set to 2.
60
        'curl_ssl_verifyhost'        => 2,
61
        // for security this should always be set to true.
62
        'curl_ssl_verifypeer'        => true,
63
64
        // you can get the latest cacert.pem from here http://curl.haxx.se/ca/cacert.pem
65
        'curl_cainfo'                => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'cacert.pem',
66
        'curl_capath'                => dirname(__FILE__),
67
68
        'curl_followlocation'        => false, // whether to follow redirects or not
69
70
        // support for proxy servers
71
        'curl_proxy'                 => false, // really you don't want to use this if you are using streaming
72
        'curl_proxyuserpwd'          => false, // format username:password for proxy, if required
73
        'curl_encoding'              => '',    // leave blank for all supported formats, else use gzip, deflate, identity
74
75
        // streaming API
76
        'is_streaming'               => false,
77
        'streaming_eol'              => "\r\n",
78
        'streaming_metrics_interval' => 60,
79
80
        // header or querystring. You should always use header!
81
        // this is just to help me debug other developers implementations
82
        'as_header'                  => true,
83
        'debug'                      => false,
84
      ),
85
      $config
86
    );
87
    $this->set_user_agent();
88
    date_default_timezone_set($this->config['timezone']);
89
90
  }
91
92
  private function set_user_agent() {
93
    if (!empty($this->config['user_agent']))
94
      return;
95
96
    if ($this->config['curl_ssl_verifyhost'] && $this->config['curl_ssl_verifypeer']) {
97
      $ssl = '+SSL';
98
    } else {
99
      $ssl = '-SSL';
100
    }
101
102
    $ua = 'tmhOAuth ' . self::VERSION . $ssl . ' - //github.com/themattharris/tmhOAuth';
103
    $this->config['user_agent'] = $ua;
104
  }
105
106
  /**
107
   * Generates a random OAuth nonce.
108
   * If 'force_nonce' is true a nonce is not generated and the value in the configuration will be retained.
109
   *
110
   * @param string $length how many characters the nonce should be before MD5 hashing. default 12
111
   * @param string $include_time whether to include time at the beginning of the nonce. default true
112
   * @return void
113
   */
114
  private function create_nonce($length=12, $include_time=true) {
115
    if ($this->config['force_nonce'] == false) {
116
      $sequence = array_merge(range(0,9), range('A','Z'), range('a','z'));
117
      $length = $length > count($sequence) ? count($sequence) : $length;
118
      shuffle($sequence);
119
120
      $prefix = $include_time ? microtime() : '';
121
      $this->config['nonce'] = md5(substr($prefix . implode('', $sequence), 0, $length));
122
    }
123
  }
124
125
  /**
126
   * Generates a timestamp.
127
   * If 'force_timestamp' is true a nonce is not generated and the value in the configuration will be retained.
128
   *
129
   * @return void
130
   */
131
  private function create_timestamp() {
132
    $this->config['timestamp'] = ($this->config['force_timestamp'] == false ? time() : $this->config['timestamp']);
133
  }
134
135
  /**
136
   * Encodes the string or array passed in a way compatible with OAuth.
137
   * If an array is passed each array value will will be encoded.
138
   *
139
   * @param mixed $data the scalar or array to encode
140
   * @return $data encoded in a way compatible with OAuth
0 ignored issues
show
Documentation introduced by
The doc-type $data could not be parsed: Unknown type name "$data" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
141
   */
142
  private function safe_encode($data) {
143
    if (is_array($data)) {
144
      return array_map(array($this, 'safe_encode'), $data);
145
    } else if (is_scalar($data)) {
146
      return str_ireplace(
147
        array('+', '%7E'),
148
        array(' ', '~'),
149
        rawurlencode($data)
150
      );
151
    } else {
152
      return '';
153
    }
154
  }
155
156
  /**
157
   * Decodes the string or array from it's URL encoded form
158
   * If an array is passed each array value will will be decoded.
159
   *
160
   * @param mixed $data the scalar or array to decode
161
   * @return $data decoded from the URL encoded form
0 ignored issues
show
Documentation introduced by
The doc-type $data could not be parsed: Unknown type name "$data" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
162
   */
163
  private function safe_decode($data) {
164
    if (is_array($data)) {
165
      return array_map(array($this, 'safe_decode'), $data);
166
    } else if (is_scalar($data)) {
167
      return rawurldecode($data);
168
    } else {
169
      return '';
170
    }
171
  }
172
173
  /**
174
   * Returns an array of the standard OAuth parameters.
175
   *
176
   * @return array all required OAuth parameters, safely encoded
177
   */
178
  private function get_defaults() {
179
    $defaults = array(
180
      'oauth_version'          => $this->config['oauth_version'],
181
      'oauth_nonce'            => $this->config['nonce'],
182
      'oauth_timestamp'        => $this->config['timestamp'],
183
      'oauth_consumer_key'     => $this->config['consumer_key'],
184
      'oauth_signature_method' => $this->config['oauth_signature_method'],
185
    );
186
187
    // include the user token if it exists
188
    if ( $this->config['user_token'] )
189
      $defaults['oauth_token'] = $this->config['user_token'];
190
191
    // safely encode
192
    foreach ($defaults as $k => $v) {
193
      $_defaults[$this->safe_encode($k)] = $this->safe_encode($v);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$_defaults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $_defaults = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
194
    }
195
196
    return $_defaults;
0 ignored issues
show
Bug introduced by
The variable $_defaults does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
197
  }
198
199
  /**
200
   * Extracts and decodes OAuth parameters from the passed string
201
   *
202
   * @param string $body the response body from an OAuth flow method
203
   * @return array the response body safely decoded to an array of key => values
204
   */
205
  public function extract_params($body) {
206
    $kvs = explode('&', $body);
207
    $decoded = array();
208
    foreach ($kvs as $kv) {
209
      $kv = explode('=', $kv, 2);
210
      $kv[0] = $this->safe_decode($kv[0]);
211
      $kv[1] = $this->safe_decode($kv[1]);
212
      $decoded[$kv[0]] = $kv[1];
213
    }
214
    return $decoded;
215
  }
216
217
  /**
218
   * Prepares the HTTP method for use in the base string by converting it to
219
   * uppercase.
220
   *
221
   * @param string $method an HTTP method such as GET or POST
222
   * @return void value is stored to a class variable
223
   * @author themattharris
224
   */
225
  private function prepare_method($method) {
226
    $this->method = strtoupper($method);
227
  }
228
229
  /**
230
   * Prepares the URL for use in the base string by ripping it apart and
231
   * reconstructing it.
232
   *
233
   * Ref: 3.4.1.2
234
   *
235
   * @param string $url the request URL
236
   * @return void value is stored to a class variable
237
   * @author themattharris
238
   */
239
  private function prepare_url($url) {
240
    $parts = parse_url($url);
241
242
    $port   = isset($parts['port']) ? $parts['port'] : false;
243
    $scheme = $parts['scheme'];
244
    $host   = $parts['host'];
245
    $path   = isset($parts['path']) ? $parts['path'] : false;
246
247
    $port or $port = ($scheme == 'https') ? '443' : '80';
248
249
    if (($scheme == 'https' && $port != '443')
250
        || ($scheme == 'http' && $port != '80')) {
251
      $host = "$host:$port";
252
    }
253
254
    // the scheme and host MUST be lowercase
255
    $this->url = strtolower("$scheme://$host");
256
    // but not the path
257
    $this->url .= $path;
258
  }
259
260
  /**
261
   * Prepares all parameters for the base string and request.
262
   * Multipart parameters are ignored as they are not defined in the specification,
263
   * all other types of parameter are encoded for compatibility with OAuth.
264
   *
265
   * @param array $params the parameters for the request
266
   * @return void prepared values are stored in class variables
267
   */
268
  private function prepare_params($params) {
269
    // do not encode multipart parameters, leave them alone
270
    if ($this->config['multipart']) {
271
      $this->request_params = $params;
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
272
      $params = array();
273
    }
274
275
    // signing parameters are request parameters + OAuth default parameters
276
    $this->signing_params = array_merge($this->get_defaults(), (array)$params);
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
277
278
    // Remove oauth_signature if present
279
    // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
280
    if (isset($this->signing_params['oauth_signature'])) {
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
281
      unset($this->signing_params['oauth_signature']);
282
    }
283
284
    // Parameters are sorted by name, using lexicographical byte value ordering.
285
    // Ref: Spec: 9.1.1 (1)
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
286
    uksort($this->signing_params, 'strcmp');
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
287
288
    // encode. Also sort the signed parameters from the POST parameters
289
    foreach ($this->signing_params as $k => $v) {
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
290
      $k = $this->safe_encode($k);
291
      $v = $this->safe_encode($v);
292
      $_signing_params[$k] = $v;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$_signing_params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $_signing_params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
293
      $kv[] = "{$k}={$v}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$kv was never initialized. Although not strictly required by PHP, it is generally a good practice to add $kv = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
294
    }
295
296
    // auth params = the default oauth params which are present in our collection of signing params
297
    $this->auth_params = array_intersect_key($this->get_defaults(), $_signing_params);
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The variable $_signing_params does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
298
    if (isset($_signing_params['oauth_callback'])) {
299
      $this->auth_params['oauth_callback'] = $_signing_params['oauth_callback'];
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
300
      unset($_signing_params['oauth_callback']);
301
    }
302
303
    if (isset($_signing_params['oauth_verifier'])) {
304
      $this->auth_params['oauth_verifier'] = $_signing_params['oauth_verifier'];
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
305
      unset($_signing_params['oauth_verifier']);
306
    }
307
308
    // request_params is already set if we're doing multipart, if not we need to set them now
309
    if ( ! $this->config['multipart'])
310
      $this->request_params = array_diff_key($_signing_params, $this->get_defaults());
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
311
312
    // create the parameter part of the base string
313
    $this->signing_params = implode('&', $kv);
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The variable $kv does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
314
  }
315
316
  /**
317
   * Prepares the OAuth signing key
318
   *
319
   * @return void prepared signing key is stored in a class variables
320
   */
321
  private function prepare_signing_key() {
322
    $this->signing_key = $this->safe_encode($this->config['consumer_secret']) . '&' . $this->safe_encode($this->config['user_secret']);
323
  }
324
325
  /**
326
   * Prepare the base string.
327
   * Ref: Spec: 9.1.3 ("Concatenate Request Elements")
328
   *
329
   * @return void prepared base string is stored in a class variables
330
   */
331
  private function prepare_base_string() {
332
    $base = array(
333
      $this->method,
334
      $this->url,
335
      $this->signing_params
0 ignored issues
show
Bug introduced by
The property signing_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
336
    );
337
    $this->base_string = implode('&', $this->safe_encode($base));
338
  }
339
340
  /**
341
   * Prepares the Authorization header
342
   *
343
   * @return void prepared authorization header is stored in a class variables
344
   */
345
  private function prepare_auth_header() {
346
    $this->headers = array();
347
    uksort($this->auth_params, 'strcmp');
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
348
    if (!$this->config['as_header']) :
349
      $this->request_params = array_merge($this->request_params, $this->auth_params);
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
350
      return;
351
    endif;
352
353
    foreach ($this->auth_params as $k => $v) {
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
354
      $kv[] = "{$k}=\"{$v}\"";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$kv was never initialized. Although not strictly required by PHP, it is generally a good practice to add $kv = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
355
    }
356
    $this->auth_header = 'OAuth ' . implode(', ', $kv);
0 ignored issues
show
Bug introduced by
The variable $kv does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
357
    $this->headers['Authorization'] = $this->auth_header;
358
  }
359
360
  /**
361
   * Signs the request and adds the OAuth signature. This runs all the request
362
   * parameter preparation methods.
363
   *
364
   * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
365
   * @param string $url the request URL without query string parameters
366
   * @param array $params the request parameters as an array of key=value pairs
367
   * @param string $useauth whether to use authentication when making the request.
368
   */
369
  private function sign($method, $url, $params, $useauth) {
370
    $this->prepare_method($method);
371
    $this->prepare_url($url);
372
    $this->prepare_params($params);
373
374
    // we don't sign anything is we're not using auth
375
    if ($useauth) {
376
      $this->prepare_base_string();
377
      $this->prepare_signing_key();
378
379
      $this->auth_params['oauth_signature'] = $this->safe_encode(
0 ignored issues
show
Bug introduced by
The property auth_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
380
        base64_encode(
381
          hash_hmac(
382
            'sha1', $this->base_string, $this->signing_key, true
383
      )));
384
385
      $this->prepare_auth_header();
386
    }
387
  }
388
389
  /**
390
   * Make an HTTP request using this library. This method doesn't return anything.
391
   * Instead the response should be inspected directly.
392
   *
393
   * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
394
   * @param string $url the request URL without query string parameters
395
   * @param array $params the request parameters as an array of key=value pairs. Default empty array
396
   * @param string $useauth whether to use authentication when making the request. Default true
397
   * @param string $multipart whether this request contains multipart data. Default false
398
   * @param array $headers any custom headers to send with the request. Default empty array
399
   */
400
  public function request($method, $url, $params=array(), $useauth=true, $multipart=false, $headers=array()) {
401
    $this->config['multipart'] = $multipart;
402
403
    $this->create_nonce();
404
    $this->create_timestamp();
405
406
    $this->sign($method, $url, $params, $useauth);
0 ignored issues
show
Bug introduced by
It seems like $useauth defined by parameter $useauth on line 400 can also be of type boolean; however, tmhOAuth::sign() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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.

Loading history...
407
408
    if (!empty($headers))
409
      $this->headers = array_merge((array)$this->headers, (array)$headers);
410
411
    return $this->curlit();
412
  }
413
414
  /**
415
   * Make a long poll HTTP request using this library. This method is
416
   * different to the other request methods as it isn't supposed to disconnect
417
   *
418
   * Using this method expects a callback which will receive the streaming
419
   * responses.
420
   *
421
   * @param string $method the HTTP method being used. e.g. POST, GET, HEAD etc
422
   * @param string $url the request URL without query string parameters
423
   * @param array $params the request parameters as an array of key=value pairs
424
   * @param string $callback the callback function to stream the buffer to.
425
   */
426
  public function streaming_request($method, $url, $params=array(), $callback='') {
427
    if ( ! empty($callback) ) {
428
      if ( ! is_callable($callback) ) {
429
        return false;
430
      }
431
      $this->config['streaming_callback'] = $callback;
432
    }
433
    $this->metrics['start']          = time();
434
    $this->metrics['interval_start'] = $this->metrics['start'];
435
    $this->metrics['tweets']         = 0;
436
    $this->metrics['last_tweets']    = 0;
437
    $this->metrics['bytes']          = 0;
438
    $this->metrics['last_bytes']     = 0;
439
    $this->config['is_streaming']    = true;
440
    $this->request($method, $url, $params);
441
  }
442
443
  /**
444
   * Handles the updating of the current Streaming API metrics.
445
   */
446
  private function update_metrics() {
447
    $now = time();
448
    if (($this->metrics['interval_start'] + $this->config['streaming_metrics_interval']) > $now)
449
      return false;
450
451
    $this->metrics['tps'] = round( ($this->metrics['tweets'] - $this->metrics['last_tweets']) / $this->config['streaming_metrics_interval'], 2);
452
    $this->metrics['bps'] = round( ($this->metrics['bytes'] - $this->metrics['last_bytes']) / $this->config['streaming_metrics_interval'], 2);
453
454
    $this->metrics['last_bytes'] = $this->metrics['bytes'];
455
    $this->metrics['last_tweets'] = $this->metrics['tweets'];
456
    $this->metrics['interval_start'] = $now;
457
    return $this->metrics;
458
  }
459
460
  /**
461
   * Utility function to create the request URL in the requested format
462
   *
463
   * @param string $request the API method without extension
464
   * @param string $format the format of the response. Default json. Set to an empty string to exclude the format
465
   * @return string the concatenation of the host, API version, API method and format
466
   */
467
  public function url($request, $format='json') {
468
    $format = strlen($format) > 0 ? ".$format" : '';
469
    $proto  = $this->config['use_ssl'] ? 'https:/' : 'http:/';
470
471
    // backwards compatibility with v0.1
472
    if (isset($this->config['v']))
473
      $this->config['host'] = $this->config['host'] . '/' . $this->config['v'];
474
475
    $request = ltrim($request, '/');
476
477
    $pos = strlen($request) - strlen($format);
478
    if (substr($request, $pos) === $format)
479
      $request = substr_replace($request, '', $pos);
480
481
    return implode('/', array(
482
      $proto,
483
      $this->config['host'],
484
      $request . $format
485
    ));
486
  }
487
488
  /**
489
   * Public access to the private safe decode/encode methods
490
   *
491
   * @param string $text the text to transform
492
   * @param string $mode the transformation mode. either encode or decode
493
   * @return the string as transformed by the given mode
494
   */
495
  public function transformText($text, $mode='encode') {
496
    return $this->{"safe_$mode"}($text);
497
  }
498
499
  /**
500
   * Utility function to parse the returned curl headers and store them in the
501
   * class array variable.
502
   *
503
   * @param object $ch curl handle
504
   * @param string $header the response headers
505
   * @return the string length of the header
506
   */
507
  private function curlHeader($ch, $header) {
508
    $this->response['raw'] .= $header;
509
510
    list($key, $value) = array_pad(explode(':', $header, 2), 2, null);
511
    $this->response['headers'][trim($key)] = trim($value);
512
513
    return strlen($header);
514
  }
515
516
  /**
517
    * Utility function to parse the returned curl buffer and store them until
518
    * an EOL is found. The buffer for curl is an undefined size so we need
519
    * to collect the content until an EOL is found.
520
    *
521
    * This function calls the previously defined streaming callback method.
522
    *
523
    * @param object $ch curl handle
524
    * @param string $data the current curl buffer
525
    */
526
  private function curlWrite($ch, $data) {
527
    $l = strlen($data);
528
    if (strpos($data, $this->config['streaming_eol']) === false) {
529
      $this->buffer .= $data;
530
      return $l;
531
    }
532
533
    $buffered = explode($this->config['streaming_eol'], $data);
534
    $content = $this->buffer . $buffered[0];
535
536
    $this->metrics['tweets']++;
537
    $this->metrics['bytes'] += strlen($content);
538
539
    if ( ! is_callable($this->config['streaming_callback']))
540
      return 0;
541
542
    $metrics = $this->update_metrics();
543
    $stop = call_user_func(
544
      $this->config['streaming_callback'],
545
      $content,
546
      strlen($content),
547
      $metrics
548
    );
549
    $this->buffer = $buffered[1];
550
    if ($stop)
551
      return 0;
552
553
    return $l;
554
  }
555
556
  /**
557
   * Makes a curl request. Takes no parameters as all should have been prepared
558
   * by the request method
559
   *
560
   * @return void response data is stored in the class variable 'response'
561
   */
562
  private function curlit() {
563
    $this->response['raw'] = '';
564
565
    // method handling
566
    switch ($this->method) {
567
      case 'POST':
568
        break;
569
      default:
570
        // GET, DELETE request so convert the parameters to a querystring
571
        if ( ! empty($this->request_params)) {
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
572
          foreach ($this->request_params as $k => $v) {
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
573
            // Multipart params haven't been encoded yet.
574
            // Not sure why you would do a multipart GET but anyway, here's the support for it
575
            if ($this->config['multipart']) {
576
              $params[] = $this->safe_encode($k) . '=' . $this->safe_encode($v);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
577
            } else {
578
              $params[] = $k . '=' . $v;
0 ignored issues
show
Bug introduced by
The variable $params does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
579
            }
580
          }
581
          $qs = implode('&', $params);
582
          $this->url = strlen($qs) > 0 ? $this->url . '?' . $qs : $this->url;
583
          $this->request_params = array();
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
584
        }
585
        break;
586
    }
587
588
    // configure curl
589
    $c = curl_init();
590
    curl_setopt_array($c, array(
591
      CURLOPT_USERAGENT      => $this->config['user_agent'],
592
      CURLOPT_CONNECTTIMEOUT => $this->config['curl_connecttimeout'],
593
      CURLOPT_TIMEOUT        => $this->config['curl_timeout'],
594
      CURLOPT_RETURNTRANSFER => true,
595
      CURLOPT_SSL_VERIFYPEER => $this->config['curl_ssl_verifypeer'],
596
      CURLOPT_SSL_VERIFYHOST => $this->config['curl_ssl_verifyhost'],
597
598
      CURLOPT_FOLLOWLOCATION => $this->config['curl_followlocation'],
599
      CURLOPT_PROXY          => $this->config['curl_proxy'],
600
      CURLOPT_ENCODING       => $this->config['curl_encoding'],
601
      CURLOPT_URL            => $this->url,
602
      // process the headers
603
      CURLOPT_HEADERFUNCTION => array($this, 'curlHeader'),
604
      CURLOPT_HEADER         => false,
605
      CURLINFO_HEADER_OUT    => true,
606
    ));
607
608
    if ($this->config['curl_cainfo'] !== false)
609
      curl_setopt($c, CURLOPT_CAINFO, $this->config['curl_cainfo']);
610
611
    if ($this->config['curl_capath'] !== false)
612
      curl_setopt($c, CURLOPT_CAPATH, $this->config['curl_capath']);
613
614
    if ($this->config['curl_proxyuserpwd'] !== false)
615
      curl_setopt($c, CURLOPT_PROXYUSERPWD, $this->config['curl_proxyuserpwd']);
616
617
    if ($this->config['is_streaming']) {
618
      // process the body
619
      $this->response['content-length'] = 0;
620
      curl_setopt($c, CURLOPT_TIMEOUT, 0);
621
      curl_setopt($c, CURLOPT_WRITEFUNCTION, array($this, 'curlWrite'));
622
    }
623
624
    switch ($this->method) {
625
      case 'GET':
626
        break;
627
      case 'POST':
628
        curl_setopt($c, CURLOPT_POST, true);
629
        curl_setopt($c, CURLOPT_POSTFIELDS, $this->request_params);
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
630
        break;
631
      default:
632
        curl_setopt($c, CURLOPT_CUSTOMREQUEST, $this->method);
633
    }
634
635
    if ( ! empty($this->request_params) ) {
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
636
      // if not doing multipart we need to implode the parameters
637
      if ( ! $this->config['multipart'] ) {
638
        foreach ($this->request_params as $k => $v) {
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
639
          $ps[] = "{$k}={$v}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ps was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ps = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
640
        }
641
        $this->request_params = implode('&', $ps);
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The variable $ps does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
642
      }
643
      curl_setopt($c, CURLOPT_POSTFIELDS, $this->request_params);
0 ignored issues
show
Bug introduced by
The property request_params does not seem to exist. Did you mean params?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
644
    }
645
646
    if ( ! empty($this->headers)) {
647
      foreach ($this->headers as $k => $v) {
648
        $headers[] = trim($k . ': ' . $v);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$headers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $headers = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
649
      }
650
      curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
0 ignored issues
show
Bug introduced by
The variable $headers does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
651
    }
652
653
    if (isset($this->config['prevent_request']) && true == $this->config['prevent_request'])
654
      return;
655
656
    // do it!
657
    $response = curl_exec($c);
658
    $code = curl_getinfo($c, CURLINFO_HTTP_CODE);
659
    $info = curl_getinfo($c);
660
    $error = curl_error($c);
661
    $errno = curl_errno($c);
662
    curl_close($c);
663
664
    // store the response
665
    $this->response['code'] = $code;
666
    $this->response['response'] = $response;
667
    $this->response['info'] = $info;
668
    $this->response['error'] = $error;
669
    $this->response['errno'] = $errno;
670
671
    if (!isset($this->response['raw'])) {
672
      $this->response['raw'] = '';
673
    }
674
    $this->response['raw'] .= $response;
675
676
    return $code;
677
  }
678
}