GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 7642f8...15f213 )
by Jamie
07:09 queued 01:51
created

Builder::userInputError()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3
Metric Value
dl 0
loc 17
ccs 10
cts 10
cp 1
rs 9.4285
cc 3
eloc 9
nc 2
nop 3
crap 3
1
<?php
2
3
namespace OpenStack\Common\Error;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\ClientInterface;
7
use GuzzleHttp\Exception\ClientException;
8
use Psr\Http\Message\MessageInterface;
9
use Psr\Http\Message\RequestInterface;
10
use Psr\Http\Message\ResponseInterface;
11
12
/**
13
 * Class responsible for building meaningful exceptions. For HTTP problems, it produces a {@see HttpError}
14
 * exception, and supplies a error message with reasonable defaults. For user input problems, it produces a
15
 * {@see UserInputError} exception. For both, the problem is described, a potential solution is offered and
16
 * a link to further information is included.
17
 *
18
 * @package OpenStack\Common\Error
19
 */
20
class Builder
21
{
22
    /**
23
     * The default domain to use for further link documentation.
24
     *
25
     * @var string
26
     */
27
    private $docDomain = 'http://docs.php-opencloud.com/en/latest/';
28
29
    /**
30
     * The HTTP client required to validate the further links.
31
     *
32
     * @var ClientInterface
33
     */
34
    private $client;
35
36
    /**
37
     * @param ClientInterface $client
38
     */
39 2
    public function __construct(ClientInterface $client = null)
40
    {
41 2
        $this->client = $client ?: new Client();
42 2
    }
43
44
    /**
45
     * Internal method used when outputting headers in the error description.
46
     *
47
     * @param $name
48
     *
49
     * @return string
50
     */
51 4
    private function header($name)
52
    {
53 4
        return sprintf("%s\n%s\n", $name, str_repeat('~', strlen($name)));
54
    }
55
56
    /**
57
     * Before outputting custom links, it is validated to ensure that the user is not
58
     * directed off to a broken link. If a 404 is detected, it is hidden.
59
     *
60
     * @param $link The proposed link
61
     *
62
     * @return bool
63
     */
64 2
    private function linkIsValid($link)
65
    {
66 2
        $link = $this->docDomain . $link;
67
68
        try {
69 2
            $resp = $this->client->request('HEAD', $link);
70 2
        } catch (ClientException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
71
        }
72
73 2
        return $resp->getStatusCode() < 400;
74
    }
75
76 2
    public function str(MessageInterface $message)
77
    {
78 2
        if ($message instanceof RequestInterface) {
79 2
            $msg = trim($message->getMethod() . ' '
80 2
                    . $message->getRequestTarget())
81 2
                . ' HTTP/' . $message->getProtocolVersion();
82 2
            if (!$message->hasHeader('host')) {
83 1
                $msg .= "\r\nHost: " . $message->getUri()->getHost();
84 1
            }
85 2
        } elseif ($message instanceof ResponseInterface) {
86 2
            $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
87 2
                . $message->getStatusCode() . ' '
88 2
                . $message->getReasonPhrase();
89 2
        }
90
91 2
        foreach ($message->getHeaders() as $name => $values) {
92 1
            $msg .= "\r\n{$name}: " . implode(', ', $values);
0 ignored issues
show
Bug introduced by
The variable $msg 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...
93 2
        }
94
95 2
        if ($message->getBody()->getSize() < ini_get('memory_limit')) {
96 2
            $msg .= "\r\n\r\n" . $message->getBody();
97 2
        }
98
99 2
        return $msg;
100
    }
101
102
    /**
103
     * Helper method responsible for constructing and returning {@see BadResponseError} exceptions.
104
     *
105
     * @param RequestInterface  $request  The faulty request
106
     * @param ResponseInterface $response The error-filled response
107
     *
108
     * @return BadResponseError
109
     */
110 2
    public function httpError(RequestInterface $request, ResponseInterface $response)
111
    {
112 2
        $message = $this->header('HTTP Error');
113
114 2
        $message .= sprintf("The remote server returned a \"%d %s\" error for the following transaction:\n\n",
115 2
            $response->getStatusCode(), $response->getReasonPhrase());
116
117 2
        $message .= $this->header('Request');
118 2
        $message .= trim($this->str($request)) . PHP_EOL . PHP_EOL;
119
120 2
        $message .= $this->header('Response');
121 2
        $message .= trim($this->str($response)) . PHP_EOL . PHP_EOL;
122
123 2
        $message .= $this->header('Further information');
124 2
        $message .= $this->getStatusCodeMessage($response->getStatusCode());
125
126
        $message .= "Visit http://docs.php-opencloud.com/en/latest/http-codes for more information about debugging "
127 2
            . "HTTP status codes, or file a support issue on https://github.com/php-opencloud/openstack/issues.";
128
129 2
        $e = new BadResponseError($message);
130 2
        $e->setRequest($request);
131 2
        $e->setResponse($response);
132
133 2
        return $e;
134
    }
135
136 2
    private function getStatusCodeMessage($statusCode)
137
    {
138
        $errors = [
139 2
            400 => 'Please ensure that your input values are valid and well-formed. ',
140 2
            401 => 'Please ensure that your authentication credentials are valid. ',
141 2
            404 => "Please ensure that the resource you're trying to access actually exists. ",
142 2
            500 => 'Please try this operation again once you know the remote server is operational. ',
143 2
        ];
144
145 2
        return isset($errors[$statusCode]) ? $errors[$statusCode] : '';
146
    }
147
148
    /**
149
     * Helper method responsible for constructing and returning {@see UserInputError} exceptions.
150
     *
151
     * @param string      $expectedType The type that was expected from the user
152
     * @param mixed       $userValue    The incorrect value the user actually provided
153
     * @param string|null $furtherLink  A link to further information if necessary (optional).
154
     *
155
     * @return UserInputError
156
     */
157 2
    public function userInputError($expectedType, $userValue, $furtherLink = null)
158
    {
159 2
        $message = $this->header('User Input Error');
160
161 2
        $message .= sprintf("%s was expected, but the following value was passed in:\n\n%s\n",
162 2
            $expectedType, print_r($userValue, true));
163
164 2
        $message .= "Please ensure that the value adheres to the expectation above. ";
165
166 2
        if ($furtherLink && $this->linkIsValid($furtherLink)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $furtherLink of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
167 1
            $message .= sprintf("Visit %s for more information about input arguments. ", $this->docDomain . $furtherLink);
168 1
        }
169
170 2
        $message .= 'If you run into trouble, please open a support issue on https://github.com/php-opencloud/openstack/issues.';
171
172 2
        return new UserInputError($message);
173
    }
174
}
175