Issues (9)

Security Analysis    not enabled

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/Server.php (1 issue)

Severity

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 declare(strict_types=1);
2
3
namespace Igni\Network;
4
5
use Igni\Exception\RuntimeException;
6
use Igni\Network\Exception\ClientException;
7
use Igni\Network\Exception\ServerException;
8
use Igni\Network\Server\Client;
9
use Igni\Network\Server\Configuration;
10
use Igni\Network\Server\HandlerFactory;
11
use Igni\Network\Server\Listener;
12
use Igni\Network\Server\LogWriter;
13
use Igni\Network\Server\OnCloseListener;
14
use Igni\Network\Server\OnConnectListener;
15
use Igni\Network\Server\OnReceiveListener;
16
use Igni\Network\Server\OnShutdownListener;
17
use Igni\Network\Server\OnStartListener;
18
use Igni\Network\Server\ServerStats;
19
use Psr\Log\LoggerInterface;
20
use SplQueue;
21
use Swoole\Server as SwooleServer;
22
23
use function extension_loaded;
24
25
/**
26
 * Http server implementation based on swoole extension.
27
 *
28
 * @package Igni\Http
29
 */
30
class Server implements HandlerFactory
31
{
32
    private const SWOOLE_EXT_NAME = 'swoole';
33
34
    /**
35
     * @var SwooleServer|null
36
     */
37
    protected $handler;
38
39
    /**
40
     * @var Configuration
41
     */
42
    protected $configuration;
43
44
    /**
45
     * @var SplQueue[]
46
     */
47
    protected $listeners = [];
48
49
    /**
50
     * @var LoggerInterface
51
     */
52
    protected $logger;
53
54
    /**
55
     * @var HandlerFactory
56
     */
57
    protected $handlerFactory;
58
59
    /**
60
     * @var Client[]
61
     */
62
    private $clients = [];
63
64
    /**
65
     * @var bool
66
     */
67
    private $running = false;
68
69 15
    public function __construct(
70
        Configuration $settings = null,
71
        LoggerInterface $logger = null,
72
        HandlerFactory $handlerFactory = null
73
    ) {
74 15
        if (!extension_loaded(self::SWOOLE_EXT_NAME)) {
75
            throw new RuntimeException('Swoole extenstion is missing, please install it and try again.');
76
        }
77
78 15
        $this->handlerFactory = $handlerFactory ?? $this;
79 15
        $this->configuration = $settings ?? new Configuration();
80 15
        $this->logger = new LogWriter($logger);
81 15
    }
82
83
    /**
84
     * Return server configuration.
85
     *
86
     * @return Configuration
87
     */
88 2
    public function getConfiguration(): Configuration
89
    {
90 2
        return $this->configuration;
91
    }
92
93
    /**
94
     * @param int $id
95
     * @return Client
96
     * @throws ClientException if client was not found
97
     */
98 6
    public function getClient(int $id): Client
99
    {
100 6
        if (!isset($this->clients[$id])) {
101 1
            throw ClientException::forInactiveClient($id);
102
        }
103 6
        return $this->clients[$id];
104
    }
105
106
    /**
107
     * Adds listener that is attached to server once it is run.
108
     *
109
     * @param Listener $listener
110
     */
111 11
    public function addListener(Listener $listener): void
112
    {
113 11
        $this->addListenerByType($listener, OnStartListener::class);
114 11
        $this->addListenerByType($listener, OnCloseListener::class);
115 11
        $this->addListenerByType($listener, OnConnectListener::class);
116 11
        $this->addListenerByType($listener, OnShutdownListener::class);
117 11
        $this->addListenerByType($listener, OnReceiveListener::class);
118 11
    }
119
120 11
    protected function addListenerByType(Listener $listener, string $type): void
121
    {
122 11
        if ($listener instanceof $type) {
123 11
            if (!isset($this->listeners[$type])) {
124 11
                $this->listeners[$type] = new SplQueue();
125
            }
126 11
            $this->listeners[$type]->push($listener);
127
        }
128 11
    }
129
130
    /**
131
     * Checks if listener exists.
132
     *
133
     * @param Listener $listener
134
     * @return bool
135
     */
136 1
    public function hasListener(Listener $listener): bool
137
    {
138
        /** @var SplQueue $listenerCollection */
139 1
        foreach ($this->listeners as $listenerCollection) {
140 1
            foreach ($listenerCollection as $current) {
141 1
                if ($current === $listener) {
142 1
                    return true;
143
                }
144
            }
145
        }
146
147 1
        return false;
148
    }
149
150
    /**
151
     * Returns information about server.
152
     *
153
     * @return ServerStats
154
     */
155 1
    public function getServerStats(): ServerStats
156
    {
157 1
        if (!$this->running) {
158 1
            throw ServerException::forMethodCallOnIdleServer(__METHOD__);
159
        }
160
        return new ServerStats($this->handler->stats());
161
    }
162
163
    public function createHandler(Configuration $configuration)
164
    {
165
        $flags = SWOOLE_TCP;
166
        if ($configuration->isSslEnabled()) {
167
            $flags |= SWOOLE_SSL;
168
        }
169
        $settings = $configuration->toArray();
170
        $handler = new SwooleServer($settings['address'], $settings['port'], SWOOLE_PROCESS, $flags);
171
        $handler->set($settings);
172
173
        return $handler;
174
    }
175
176 10
    public function start(): void
177
    {
178 10
        $this->addListener($this->logger);
0 ignored issues
show
$this->logger is of type object<Psr\Log\LoggerInterface>, but the function expects a object<Igni\Network\Server\Listener>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
179 10
        $this->handler = $this->handlerFactory->createHandler($this->configuration);
180 10
        $this->createListeners();
181 10
        $this->handler->start();
182 10
        $this->running = true;
183 10
    }
184
185 1
    public function stop(): void
186
    {
187 1
        if ($this->handler !== null) {
188 1
            $this->handler->shutdown();
189 1
            $this->handler = null;
190
        }
191 1
        $this->running = false;
192 1
    }
193
194 1
    public function isRunning(): bool
195
    {
196 1
        return $this->running;
197
    }
198
199 10
    protected function createListeners(): void
200
    {
201 10
        $this->createOnConnectListener();
202 10
        $this->createOnCloseListener();
203 10
        $this->createOnShutdownListener();
204 10
        $this->createOnStartListener();
205 10
        $this->createOnReceiveListener();
206 10
    }
207
208 6
    private function createClient($handler, int $clientId): Client
209
    {
210 6
        return $this->clients[$clientId] = new Client($handler, $clientId);
211
    }
212
213 4
    private function destroyClient(int $clientId): void
214
    {
215 4
        unset($this->clients[$clientId]);
216 4
    }
217
218 10
    protected function createOnConnectListener(): void
219
    {
220
        $this->handler->on('Connect', function($handler, int $clientId) {
221 6
            $this->createClient($handler, $clientId);
222
223 6
            if (!isset($this->listeners[OnConnectListener::class])) {
224
                return;
225
            }
226
227 6
            $queue = clone $this->listeners[OnConnectListener::class];
228
            /** @var OnConnectListener $listener */
229 6
            while (!$queue->isEmpty() && $listener = $queue->pop()) {
230 6
                $listener->onConnect($this, $this->getClient($clientId));
231
            }
232 10
        });
233 10
    }
234
235 10
    protected function createOnCloseListener(): void
236
    {
237
        $this->handler->on('Close', function($handler, int $clientId) {
238 4
            if (isset($this->listeners[OnCloseListener::class])) {
239
240 4
                $queue = clone $this->listeners[OnCloseListener::class];
241
                /** @var OnCloseListener $listener */
242 4
                while (!$queue->isEmpty() && $listener = $queue->pop()) {
243 4
                    $listener->onClose($this, $this->getClient($clientId));
244
                }
245
            }
246
247 4
            $this->destroyClient($clientId);
248 10
        });
249 10
    }
250
251 10
    protected function createOnShutdownListener(): void
252
    {
253
        $this->handler->on('Shutdown', function() {
254 1
            if (!isset($this->listeners[OnShutdownListener::class])) {
255
                return;
256
            }
257
258 1
            $queue = clone $this->listeners[OnShutdownListener::class];
259
260
            /** @var OnShutdownListener $listener */
261 1
            while (!$queue->isEmpty() && $listener = $queue->pop()) {
262 1
                $listener->onShutdown($this);
263
            }
264 1
            $this->clients = [];
265 10
        });
266 10
    }
267
268 10
    protected function createOnStartListener(): void
269
    {
270
        $this->handler->on('Start', function() {
271 1
            if (!isset($this->listeners[OnStartListener::class])) {
272
                return;
273
            }
274
275 1
            $queue = clone $this->listeners[OnStartListener::class];
276
            /** @var OnStartListener $listener */
277 1
            while (!$queue->isEmpty() && $listener = $queue->pop()) {
278 1
                $listener->onStart($this);
279
            }
280 10
        });
281 10
    }
282
283 10
    protected function createOnReceiveListener(): void
284
    {
285
        $this->handler->on('Receive', function ($handler, int $clientId, int $fromId, string $data) {
286 1
            if (!isset($this->listeners[OnReceiveListener::class])) {
287
                return;
288
            }
289
290 1
            $queue = clone $this->listeners[OnReceiveListener::class];
291
292
            /** @var OnReceiveListener $listener */
293 1
            while (!$queue->isEmpty() && $listener = $queue->pop()) {
294 1
                $listener->onReceive($this, $this->getClient($clientId), $data);
295
            }
296 10
        });
297 10
    }
298
}
299