Completed
Push — master ( 370c42...8a8768 )
by
unknown
05:45
created

HTTP::lastResponseHeader()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 0
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * HTTP
5
 *
6
 * cURL proxy.
7
 *
8
 * @package core
9
 * @author [email protected]
10
 * @copyright Caffeina srl - 2016 - http://caffeina.com
11
 */
12
13
class HTTP {
14
  use Module, Events;
15
16
  protected static $UA                    = "Mozilla/4.0 (compatible; Core::HTTP; Windows NT 6.1)",
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
17
                   $json_data             = false,
18
                   $headers               = [],
19
                   $last_response_header  = null,
20
                   $last_response_body    = null,
21
                   $last_info             = null,
22
                   $proxy                 = null; // host:port
23
24
  protected static function request($method, $url, $data=[], array $headers=[], $data_as_json=false, $username=null, $password = null){
25
    $http_method = strtoupper($method);
26
    $ch  = curl_init($url);
27
    $opt = [
28
      CURLOPT_CUSTOMREQUEST   => $http_method,
29
      CURLOPT_SSL_VERIFYHOST  => false,
30
      CURLOPT_CONNECTTIMEOUT  => 10,
31
      CURLOPT_RETURNTRANSFER  => true,
32
      CURLOPT_USERAGENT       => static::$UA,
33
      CURLOPT_HEADER          => true,
34
      CURLOPT_VERBOSE         => true,
35
      CURLOPT_MAXREDIRS       => 10,
36
      CURLOPT_FOLLOWLOCATION  => true,
37
      CURLOPT_ENCODING        => '',
38
      CURLOPT_PROXY           => static::$proxy,
39
    ];
40
41
    if($username && $password) {
42
      $opt[CURLOPT_USERPWD] = "$username:$password";
43
    }
44
45
    $headers = array_merge($headers,static::$headers);
46
47
    if($http_method == 'GET'){
48
        if($data && is_array($data)){
49
          $tmp                       = [];
50
          $queried_url               = $url;
51
          foreach($data as $key=>$val) $tmp[] = $key.'='.$val;
52
          $queried_url               .= (strpos($queried_url,'?') === false) ? '?' : '&';
53
          $queried_url               .= implode('&',$tmp);
54
          $opt[CURLOPT_URL]          = $queried_url;
55
          $opt[CURLOPT_HTTPGET]      = true;
56
          unset($opt[CURLOPT_CUSTOMREQUEST]);
57
        }
58
    } else {
59
        $opt[CURLOPT_CUSTOMREQUEST]  = $http_method;
60
        if($data_as_json or is_object($data)){
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
61
          $headers['Content-Type']   = 'application/json';
62
          $opt[CURLOPT_POSTFIELDS]   = json_encode($data);
63
        } else {
64
          $opt[CURLOPT_POSTFIELDS]   = http_build_query($data);
65
        }
66
    }
67
68
    curl_setopt_array($ch,$opt);
69
    $_harr = [];
70
    foreach($headers as $key=>$val)  $_harr[] = $key.': '.$val;
71
    curl_setopt($ch, CURLOPT_HTTPHEADER, $_harr);
72
    $result = curl_exec($ch);
73
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
74
    $contentType = strtolower(curl_getinfo($ch, CURLINFO_CONTENT_TYPE));
75
    static::$last_response_header = substr($result, 0, $header_size);
76
    $result = substr($result, $header_size);
77
    static::$last_info = curl_getinfo($ch);
78
    if(false !== strpos($contentType,'json')) $result = json_decode($result);
79
    curl_close($ch);
80
    static::trigger("request", $result, static::$last_info);
81
    static::$last_response_body = $result;
82
    return $result;
83
  }
84
85
  public static function useJSON($value=null){
86
    return $value===null ? static::$json_data : static::$json_data = $value;
87
  }
88
89
  protected static function trasformRawHeaders($headers,$url) {
0 ignored issues
show
Unused Code introduced by
The parameter $url is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
90
    foreach (explode("\r\n", trim($headers)) as $line) {
91
      if (empty($line)) continue;
92
      $splitted = explode(': ', $line);
93
      if (count($splitted) == 2) {
94
        list ($key, $value) = explode(': ', $line);
95
        $res[$key] = $value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$res was never initialized. Although not strictly required by PHP, it is generally a good practice to add $res = 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...
96
      } else $res['http_code'][] = $line;
0 ignored issues
show
Bug introduced by
The variable $res 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...
97
    }
98
    if (count($res['http_code']) == 1) $res['http_code'] = $res['http_code'][0];
99
    return $res;
100
  }
101
102
  public static function lastResponseBody(){
103
    return static::$last_response_body;
104
  }
105
106
  public static function lastResponseHeader(){
107
    if (static::$last_response_header && !is_array(static::$last_response_header)) {
108
      static::$last_response_header = static::trasformRawHeaders(static::$last_response_header);
0 ignored issues
show
Bug introduced by
The call to trasformRawHeaders() misses a required argument $url.

This check looks for function calls that miss required arguments.

Loading history...
109
    }
110
    return static::$last_response_header;
111
  }
112
113
  public static function addHeader($name,$value){
114
    static::$headers[$name] = $value;
115
  }
116
117
  public static function removeHeader($name){
118
    unset(static::$headers[$name]);
119
  }
120
121
  public static function headers($name=null){
122
    // null === $name ?? static::$headers ?? static::$headers[$name]
123
    return null === $name
124
           ? static::$headers
125
           : ( isset(static::$headers[$name]) ? static::$headers[$name] : '' );
126
  }
127
128
  public static function userAgent($value=null){
129
    return $value===null ? static::$UA : static::$UA = $value;
130
  }
131
132
  public static function proxy($value=false){
133
    return $value===false ? static::$proxy : static::$proxy = $value;
134
  }
135
136
  public static function get($url, $data=null, array $headers=[], $username = null, $password = null){
137
    return static::request('get',$url,$data,$headers,false,$username,$password);
138
  }
139
140
  public static function post($url, $data=null, array $headers=[], $username = null, $password = null){
141
    return static::request('post',$url,$data,$headers,static::$json_data,$username,$password);
142
  }
143
144
  public static function put($url, $data=null, array $headers=[], $username = null, $password = null){
145
    return static::request('put',$url,$data,$headers,static::$json_data,$username,$password);
146
  }
147
148
  public static function delete($url, $data=null, array $headers=[], $username = null, $password = null){
149
    return static::request('delete',$url,$data,$headers,static::$json_data,$username,$password);
150
  }
151
152
  public static function info($url = null){
153
    if ($url){
154
      curl_setopt_array($ch = curl_init($url), [
155
        CURLOPT_SSL_VERIFYHOST  => false,
156
        CURLOPT_CONNECTTIMEOUT  => 10,
157
        CURLOPT_RETURNTRANSFER  => true,
158
        CURLOPT_USERAGENT       => static::$UA,
159
        CURLOPT_HEADER          => false,
160
        CURLOPT_ENCODING        => '',
161
        CURLOPT_FILETIME        => true,
162
        CURLOPT_NOBODY          => true,
163
        CURLOPT_PROXY           => static::$proxy,
164
      ]);
165
      curl_exec($ch);
166
      $info = curl_getinfo($ch);
167
      curl_close($ch);
168
      return $info;
169
    } else {
170
      return static::$last_info;
171
    }
172
  }
173
174
}
175
176
class HTTP_Request {
177
  public $method   = 'GET',
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
178
         $url      = null,
179
         $headers  = [],
180
         $body     = '';
181
182
  public function __construct($method, $url, $headers=[], $data=null){
0 ignored issues
show
Unused Code introduced by
The parameter $url is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
183
    $this->method   = strtoupper($method);
184
    $this->url      = new URL($this->url);
185
    $this->headers  = (array)$headers;
186
    if ($data) {
187
      if (isset($this->headers["Content-Type"]) && $this->headers["Content-Type"]=='application/json')
188
        $this->body = json_encode($data);
189
      else
190
        $this->body = http_build_query($data);
191
    }
192
  }
193
194
  public function __toString(){
195
    return "$this->method {$this->url->path}{$this->url->query} HTTP/1.1\r\n"
0 ignored issues
show
Documentation introduced by
The property $path is declared private in URL. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property $query is declared private in URL. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
196
          ."Host: {$this->url->host}\r\n"
0 ignored issues
show
Documentation introduced by
The property $host is declared private in URL. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
197
          .($this->headers ? implode("\r\n",$this->headers) . "\r\n" : '')
198
          ."\r\n{$this->body}";
199
  }
200
}
201
202
203
class HTTP_Response {
204
  public $status   = 200,
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
205
         $headers  = [],
206
         $contents = '';
207
208
  public function __construct($contents, $status, $headers){
209
    $this->status   = $status;
210
    $this->contents = $contents;
211
    $this->headers  = (array)$headers;
212
  }
213
214
  public function __toString(){
215
    return $this->contents;
216
  }
217
}
218
219