HTTP::post()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 5
dl 0
loc 3
rs 10
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)",
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
    preg_match('/.+(?::([0-9]+))\/?/i', $url, $match);
26
    $port = count($match) > 1 ? $match[1] : 80;
27
    $http_method = strtoupper($method);
28
    $ch  = curl_init($url);
29
    $opt = [
30
      CURLOPT_CUSTOMREQUEST   => $http_method,
31
      CURLOPT_SSL_VERIFYHOST  => false,
32
      CURLOPT_CONNECTTIMEOUT  => 10,
33
      CURLOPT_RETURNTRANSFER  => true,
34
      CURLOPT_USERAGENT       => static::$UA,
35
      CURLOPT_HEADER          => true,
36
      CURLOPT_VERBOSE         => true,
37
      CURLOPT_MAXREDIRS       => 10,
38
      CURLOPT_FOLLOWLOCATION  => true,
39
      CURLOPT_ENCODING        => '',
40
      CURLOPT_PROXY           => static::$proxy,
41
      CURLOPT_PORT            => $port
42
    ];
43
44
    if($username && $password) {
45
      $opt[CURLOPT_USERPWD] = "$username:$password";
46
    }
47
48
    $headers = array_merge($headers,static::$headers);
49
50
    if($http_method == 'GET'){
51
        if($data && is_array($data)){
52
          $tmp                       = [];
53
          $queried_url               = $url;
54
          foreach($data as $key=>$val) $tmp[] = $key.'='.$val;
55
          $queried_url               .= (strpos($queried_url,'?') === false) ? '?' : '&';
56
          $queried_url               .= implode('&',$tmp);
57
          $opt[CURLOPT_URL]          = $queried_url;
58
          $opt[CURLOPT_HTTPGET]      = true;
59
          unset($opt[CURLOPT_CUSTOMREQUEST]);
60
        }
61
    } else {
62
        $opt[CURLOPT_CUSTOMREQUEST]  = $http_method;
63
        if($data_as_json or is_object($data)){
64
          $headers['Content-Type']   = 'application/json';
65
          $opt[CURLOPT_POSTFIELDS]   = json_encode($data);
66
        } else {
67
          $opt[CURLOPT_POSTFIELDS]   = http_build_query($data);
68
        }
69
    }
70
71
    curl_setopt_array($ch,$opt);
72
    $_harr = [];
73
    foreach($headers as $key=>$val)  $_harr[] = $key.': '.$val;
74
    curl_setopt($ch, CURLOPT_HTTPHEADER, $_harr);
75
    $result = curl_exec($ch);
76
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
77
    $contentType = strtolower(curl_getinfo($ch, CURLINFO_CONTENT_TYPE));
78
    static::$last_response_header = substr($result, 0, $header_size);
79
    $result = substr($result, $header_size);
80
    static::$last_info = curl_getinfo($ch);
81
    if(false !== strpos($contentType,'json')) $result = json_decode($result);
82
    curl_close($ch);
83
    static::trigger("request", $result, static::$last_info);
84
    static::$last_response_body = $result;
85
    return $result;
86
  }
87
88
  public static function useJSON($value=null){
89
    return $value===null ? static::$json_data : static::$json_data = $value;
90
  }
91
92
  protected static function trasformRawHeaders($headers) {
93
    foreach (explode("\r\n", trim($headers)) as $line) {
94
      if (empty($line)) continue;
95
      $splitted = explode(':', $line);
96
      $res[isset($splitted[1])? trim($splitted[0]) : 'extra'][] = trim(end($splitted));
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...
97
    }
98
    return $res;
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...
99
  }
100
101
  public static function lastResponseBody(){
102
    return static::$last_response_body;
103
  }
104
105
  public static function lastResponseHeader(){
106
    if (static::$last_response_header && !is_array(static::$last_response_header)) {
107
      static::$last_response_header = static::trasformRawHeaders(static::$last_response_header);
108
    }
109
    return static::$last_response_header;
110
  }
111
112
  public static function addHeader($name,$value){
113
    static::$headers[$name] = $value;
114
  }
115
116
  public static function removeHeader($name){
117
    unset(static::$headers[$name]);
118
  }
119
120
  public static function headers($name=null){
121
    // null === $name ?? static::$headers ?? static::$headers[$name]
122
    return null === $name
123
           ? static::$headers
124
           : ( isset(static::$headers[$name]) ? static::$headers[$name] : '' );
125
  }
126
127
  public static function userAgent($value=null){
128
    return $value===null ? static::$UA : static::$UA = $value;
129
  }
130
131
  public static function proxy($value=false){
132
    return $value===false ? static::$proxy : static::$proxy = $value;
133
  }
134
135
  public static function get($url, $data=null, array $headers=[], $username = null, $password = null){
136
    return static::request('get',$url,$data,$headers,false,$username,$password);
137
  }
138
139
  public static function post($url, $data=null, array $headers=[], $username = null, $password = null){
140
    return static::request('post',$url,$data,$headers,static::$json_data,$username,$password);
141
  }
142
143
  public static function put($url, $data=null, array $headers=[], $username = null, $password = null){
144
    return static::request('put',$url,$data,$headers,static::$json_data,$username,$password);
145
  }
146
147
  public static function delete($url, $data=null, array $headers=[], $username = null, $password = null){
148
    return static::request('delete',$url,$data,$headers,static::$json_data,$username,$password);
149
  }
150
151
  public static function info($url = null){
152
    if ($url){
153
      curl_setopt_array($ch = curl_init($url), [
154
        CURLOPT_SSL_VERIFYHOST  => false,
155
        CURLOPT_CONNECTTIMEOUT  => 10,
156
        CURLOPT_RETURNTRANSFER  => true,
157
        CURLOPT_USERAGENT       => static::$UA,
158
        CURLOPT_HEADER          => false,
159
        CURLOPT_ENCODING        => '',
160
        CURLOPT_FILETIME        => true,
161
        CURLOPT_NOBODY          => true,
162
        CURLOPT_PROXY           => static::$proxy,
163
      ]);
164
      curl_exec($ch);
165
      $info = curl_getinfo($ch);
166
      curl_close($ch);
167
      return $info;
168
    } else {
169
      return static::$last_info;
170
    }
171
  }
172
173
}
174
175
class HTTP_Request {
176
  public $method   = 'GET',
177
         $url      = null,
178
         $headers  = [],
179
         $body     = '';
180
181
  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...
182
    $this->method   = strtoupper($method);
183
    $this->url      = new URL($this->url);
184
    $this->headers  = (array)$headers;
185
    if ($data) {
186
      if (isset($this->headers["Content-Type"]) && $this->headers["Content-Type"]=='application/json')
187
        $this->body = json_encode($data);
188
      else
189
        $this->body = http_build_query($data);
190
    }
191
  }
192
193
  public function __toString(){
194
    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...
195
          ."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...
196
          .($this->headers ? implode("\r\n",$this->headers) . "\r\n" : '')
197
          ."\r\n{$this->body}";
198
  }
199
}
200
201
202
class HTTP_Response {
203
  public $status   = 200,
204
         $headers  = [],
205
         $contents = '';
206
207
  public function __construct($contents, $status, $headers){
208
    $this->status   = $status;
209
    $this->contents = $contents;
210
    $this->headers  = (array)$headers;
211
  }
212
213
  public function __toString(){
214
    return $this->contents;
215
  }
216
}
217
218