Failed Conditions
Pull Request — master (#8)
by Mateusz
03:32
created

src/HttpClient.php (4 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
3
/*
4
 * This file is part of the puli/installer package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Installer;
13
14
use RuntimeException;
15
16
/**
17
 * Downloads files.
18
 *
19
 * This file was adapted from the installer file bundled with Composer. For the
20
 * original file, authors and copyright information see
21
 *
22
 * https://github.com/composer/getcomposer.org/blob/master/web/installer
23
 *
24
 * @author Nils Adermann <[email protected]>
25
 * @author Jordi Boggiano <[email protected]>
26
 * @author Thomas Rudolph <[email protected]>
27
 * @author Bernhard Schussek <[email protected]>
28
 */
29
class HttpClient
30
{
31
    /**
32
     * @var array
33
     */
34
    private $headers = array(
35
        "Connection: close\r\n",
36
        "User-Agent: Puli Installer\r\n",
37
    );
38
39
    /**
40
     * @var bool
41
     */
42
    private $tls = false;
43
44
    /**
45
     * Creates the HTTP client.
46
     *
47
     * @param bool $disableTls Whether to disable TLS.
48
     */
49 5
    public function __construct($disableTls = false)
50
    {
51 5
        $this->tls = !$disableTls;
52
53 5
        if (extension_loaded('zlib')) {
54 5
            $this->headers[] = "Accept-Encoding: gzip\r\n";
55 5
        }
56 5
    }
57
58
    /**
59
     * Downloads a file.
60
     *
61
     * @param string $url The URL of the file to download.
62
     *
63
     * @return string The downloaded file body.
64
     */
65 5
    public function download($url)
66
    {
67 5
        if ($this->tls) {
68 5
            humbug_set_headers($this->headers);
69 5
            $result = humbug_get_contents($url);
70 5
        } else {
71
            $context = $this->getNonSslStreamContext($url);
72
            $result = file_get_contents($url, null, $context);
73
        }
74
75 5
        if ($result && extension_loaded('zlib')) {
76 5
            $decode = false;
77 5
            $responseHeaders = $this->tls ? humbug_get_headers() : $http_response_header;
0 ignored issues
show
The variable $http_response_header 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...
78
79 5
            foreach ($responseHeaders as $header) {
80 5
                if (preg_match('{^content-encoding: *gzip *$}i', $header)) {
81
                    $decode = true;
82
                    continue;
83 5
                } elseif (preg_match('{^HTTP/}i', $header)) {
84 5
                    $decode = false;
85 5
                }
86 5
            }
87
88 5
            if ($decode) {
89
                $result = version_compare(PHP_VERSION, '5.4.0', '>=')
90
                    ? zlib_decode($result)
91
                    // work around issue with gzuncompress & co that do not work with all gzip checksums
92
                    : file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
93
94
                if (!$result) {
95
                    throw new RuntimeException('Failed to decode zlib stream');
96
                }
97
            }
98 5
        }
99
100 5
        return $result;
101
    }
102
103
    private function getNonSslStreamContext($url)
0 ignored issues
show
getNonSslStreamContext uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
104
    {
105
        // Handle system proxy
106
        if (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy'])) {
107
            // Some systems seem to rely on a lowercased version instead...
108
            $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
109
        }
110
111
        if (!empty($proxy)) {
112
            $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'].'://' : '';
113
            $proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';
114
115
            if (isset($proxy['port'])) {
116
                $proxyURL .= ':'.$proxy['port'];
117
            } elseif ('http://' === substr($proxyURL, 0, 7)) {
118
                $proxyURL .= ':80';
119
            } elseif ('https://' === substr($proxyURL, 0, 8)) {
120
                $proxyURL .= ':443';
121
            }
122
123
            // http(s):// is not supported in proxy
124
            $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);
125
126
            if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
127
                throw new RuntimeException('You must enable the openssl extension to use a proxy over https');
128
            }
129
130
            $options['http'] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = 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...
131
                'proxy' => $proxyURL,
132
            );
133
134
            // enabled request_fulluri unless it is explicitly disabled
135
            switch (parse_url($url, PHP_URL_SCHEME)) {
136 View Code Duplication
                case 'http': // default request_fulluri to true
137
                    $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI');
138
                    if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
139
                        $options['http']['request_fulluri'] = true;
140
                    }
141
                    break;
142 View Code Duplication
                case 'https': // default request_fulluri to true
143
                    $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI');
144
                    if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
145
                        $options['http']['request_fulluri'] = true;
146
                    }
147
                    break;
148
            }
149
150
            if (isset($proxy['user'])) {
151
                $auth = urldecode($proxy['user']);
152
                if (isset($proxy['pass'])) {
153
                    $auth .= ':'.urldecode($proxy['pass']);
154
                }
155
                $auth = base64_encode($auth);
156
157
                $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n";
158
            }
159
        }
160
161
        if (isset($options['http']['header'])) {
162
            $options['http']['header'] .= implode('', $this->headers);
163
        } else {
164
            $options['http']['header'] = implode('', $this->headers);
0 ignored issues
show
The variable $options 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...
165
        }
166
167
        $options['http']['protocol_version'] = 1.1;
168
169
        return stream_context_create($options);
170
    }
171
}
172