Issues (33)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Client.php (9 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
namespace Bouhnosaure\Dogecoin;
4
5
use GuzzleHttp\Client as GuzzleHttp;
6
use GuzzleHttp\ClientInterface;
7
use GuzzleHttp\Exception\RequestException;
8
use GuzzleHttp\HandlerStack;
9
use GuzzleHttp\Middleware;
10
use Psr\Http\Message\ResponseInterface;
11
12
class Client
13
{
14
    /**
15
     * Http Client.
16
     *
17
     * @var \GuzzleHttp\Client
18
     */
19
    protected $client = null;
20
21
    /**
22
     * JSON-RPC Id.
23
     *
24
     * @var int
25
     */
26
    protected $rpcId = 0;
27
28
    /**
29
     * Constructs new client.
30
     *
31
     * @param mixed $config
32
     *
33
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
34
     */
35 78
    public function __construct($config = [])
36
    {
37
        // init defaults
38 78
        $config = $this->defaultConfig($this->parseUrl($config));
39
40 78
        $handlerStack = HandlerStack::create();
41 78
        $handlerStack->push(
42 78
            Middleware::mapResponse(function (ResponseInterface $response) {
43 30
                return DogecoindResponse::createFrom($response);
44 78
            }),
45 52
            'json_response'
46 26
        );
47
48
        // construct client
49 78
        $this->client = new GuzzleHttp([
50 26
            'base_uri' => "${config['scheme']}://${config['host']}:${config['port']}",
51
            'auth' => [
52 78
                $config['user'],
53 78
                $config['pass'],
54 26
            ],
55 78
            'verify' => isset($config['ca']) && is_file($config['ca']) ?
56 28
                $config['ca'] : true,
57 78
            'handler' => $handlerStack,
58 26
        ]);
59 78
    }
60
61
    /**
62
     * Gets http client config.
63
     *
64
     * @param string|null $option
65
     *
66
     * @return mixed
67
     */
68
    public function getConfig($option = null)
69
    {
70
        return (
71 66
            isset($this->client) &&
72 66
            $this->client instanceof ClientInterface
73 66
        ) ? $this->client->getConfig($option) : false;
74
    }
75
76
    /**
77
     * Gets http client.
78
     *
79
     * @return \GuzzleHttp\ClientInterface
80
     */
81
    public function getClient()
82
    {
83 3
        return $this->client;
84
    }
85
86
    /**
87
     * Sets http client.
88
     *
89
     * @param  \GuzzleHttp\ClientInterface
90
     *
91
     * @return Client
92
     */
93
    public function setClient(ClientInterface $client)
94
    {
95 45
        $this->client = $client;
0 ignored issues
show
Documentation Bug introduced by
$client is of type object<GuzzleHttp\ClientInterface>, but the property $client was declared to be of type object<GuzzleHttp\Client>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
96
97 45
        return $this;
98
    }
99
100
    /**
101
     * Makes request to Dogecoin Core.
102
     *
103
     * @param string $method
104
     * @param mixed $params
105
     *
106
     * @return array
107
     */
108
    public function request($method, $params = [])
109
    {
110
        try {
111
            $json = [
112 21
                'method' => strtolower($method),
113 21
                'params' => (array)$params,
114 21
                'id' => $this->rpcId++,
115 7
            ];
116
117 21
            $response = $this->client->request('POST', '/', ['json' => $json]);
118
119 9
            if ($response->hasError()) {
120
                // throw exception on error
121 3
                throw new Exceptions\DogecoindException($response->error());
122
            }
123
124 6
            return $response;
125 15
        } catch (RequestException $exception) {
126 12
            if ($exception->hasResponse() &&
127 11
                $exception->getResponse()->hasError()
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method hasError() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
128 4
            ) {
129 6
                throw new Exceptions\DogecoindException($exception->getResponse()->error());
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method error() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
130 1
            }
131
132 6
            throw new Exceptions\ClientException(
133 6
                $exception->getMessage(),
134 6
                $exception->getCode()
135 2
            );
136 3
        } catch (Exceptions\DogecoindException $exception) {
137 3
            throw $exception;
138
        }
139
    }
140
141
    /**
142
     * Makes async request to Dogecoin Core.
143
     *
144
     * @param string $method
145
     * @param mixed $params
146
     * @param callable|null $onFullfiled
147
     * @param callable|null $onRejected
148
     *
149
     * @return \GuzzleHttp\Promise\PromiseInterface
150
     */
151
    public function requestAsync(
152
        $method,
153
        $params = [],
154
        callable $onFullfiled = null,
155
        callable $onRejected = null
156
    ) {
157
    
158
159
        $json = [
160 21
            'method' => strtolower($method),
161 21
            'params' => (array)$params,
162 21
            'id' => $this->rpcId++,
163 7
        ];
164
165 21
        $promise = $this->client
166 21
            ->requestAsync('POST', '/', ['json' => $json]);
167
168 21
        $promise->then(
169
            function (ResponseInterface $response) use ($onFullfiled) {
170 9
                $error = null;
171 9
                if ($response->hasError()) {
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method hasError() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
172 3
                    $error = new Exceptions\DogecoindException($response->error());
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method error() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
173 1
                }
174
175 9
                if (is_callable($onFullfiled)) {
176 9
                    $onFullfiled($error ?: $response);
177 3
                }
178 21
            },
179
            function (RequestException $exception) use ($onRejected) {
180 12
                if ($exception->hasResponse() &&
181 11
                    $exception->getResponse()->hasError()
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method hasError() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
182 4
                ) {
183 6
                    $exception = new Exceptions\DogecoindException(
184 6
                        $exception->getResponse()->error()
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method error() does only exist in the following implementations of said interface: Bouhnosaure\Dogecoin\DogecoindResponse.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
185 2
                    );
186 2
                }
187
188 12
                if ($exception instanceof RequestException) {
189 6
                    $exception = new Exceptions\ClientException(
190 6
                        $exception->getMessage(),
191 6
                        $exception->getCode()
192 2
                    );
193 2
                }
194
195 12
                if (is_callable($onRejected)) {
196 12
                    $onRejected($exception);
197 4
                }
198 18
            }
199 7
        );
200
201 21
        return $promise;
202
    }
203
204
    /**
205
     * Makes request to Dogecoin Core.
206
     *
207
     * @param string $method
208
     * @param array $params
209
     *
210
     * @return array|\GuzzleHttp\Promise\PromiseInterface
211
     */
212
    public function __call($method, array $params = [])
213
    {
214 21
        $method = str_ireplace('async', '', $method, $count);
215 21
        if ($count > 0) {
216 3
            return $this->requestAsync($method, ...$params);
217
        }
218
219 18
        return $this->request($method, $params);
220
    }
221
222
    /**
223
     * Set default config values.
224
     *
225
     * @param array $config
226
     *
227
     * @return array
228
     */
229
    protected function defaultConfig(array $config = [])
230
    {
231
        $defaults = [
232 78
            'scheme' => 'http',
233 26
            'host' => '127.0.0.1',
234 26
            'port' => 22555,
235 26
            'user' => '',
236 26
            'pass' => '',
237 26
        ];
238
239 78
        return array_merge($defaults, $config);
240
    }
241
242
    /**
243
     * Expand URL config into components.
244
     *
245
     * @param mixed $config
246
     *
247
     * @return array
248
     */
249
    protected function parseUrl($config)
250
    {
251 78
        if (is_string($config)) {
252 24
            $allowed = ['scheme', 'host', 'port', 'user', 'pass'];
253
254 24
            $parts = (array)parse_url($config);
255 24
            $parts = array_intersect_key($parts, array_flip($allowed));
256
257 24
            if (!$parts || empty($parts)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parts of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
258 3
                throw new Exceptions\ClientException('Invalid url');
259
            }
260
261 21
            return $parts;
262
        }
263
264 78
        return $config;
265
    }
266
267
    /**
268
     * Converts amount from shibetoshi to dogecoin.
269
     *
270
     * @param int $amount
271
     *
272
     * @return float
273
     */
274
    public static function toDogecoin($amount)
275
    {
276 3
        return bcdiv((int)$amount, 1e8, 8);
277
    }
278
279
    /**
280
     * Converts amount from dogecoin to shibetoshi.
281
     *
282
     * @param float $amount
283
     *
284
     * @return int
285
     */
286
    public static function toShibetoshi($amount)
287
    {
288 3
        return bcmul(static::toFixed($amount, 8), 1e8);
289
    }
290
291
    /**
292
     * Converts amount from dogecoin to Koinu.
293
     *
294
     * @param float $amount
295
     *
296
     * @return int
297
     */
298
    public static function toKoinu($amount)
299
    {
300
        return self::toShibetoshi($amount);
301
    }
302
303
304
    /**
305
     * Brings number to fixed pricision without rounding.
306
     *
307
     * @param float $number
308
     * @param int $precision
309
     *
310
     * @return string
311
     */
312
    public static function toFixed($number, $precision = 8)
313
    {
314 6
        $number = $number * pow(10, $precision);
315
316 6
        return bcdiv($number, pow(10, $precision), $precision);
317
    }
318
}
319