Issues (11)

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/Client.php (3 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
 * This file is part of the Ssdp project.
4
 *
5
 * @author Daniel Schröder <[email protected]>
6
 */
7
8
namespace GravityMedia\Ssdp;
9
10
use GravityMedia\Ssdp\Event\DiscoverEvent;
11
use GravityMedia\Ssdp\Exception\DiscoverException;
12
use GravityMedia\Ssdp\Multicast\Factory as MulticastFactory;
13
use GravityMedia\Ssdp\Options\AliveOptions;
14
use GravityMedia\Ssdp\Options\ByebyeOptions;
15
use GravityMedia\Ssdp\Options\DiscoverOptions;
16
use GravityMedia\Ssdp\Options\UpdateOptions;
17
use GravityMedia\Ssdp\Request\Factory as RequestFactory;
18
use Psr\Http\Message\RequestInterface;
19
use Socket\Raw\Exception as SocketException;
20
use Socket\Raw\Socket;
21
use Symfony\Component\EventDispatcher\EventDispatcher;
22
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
23
use Zend\Diactoros\Request\Serializer as RequestSerializer;
24
use Zend\Diactoros\Response\Serializer as ResponseSerializer;
25
use Zend\Diactoros\Uri;
26
27
/**
28
 * Ssdp client class
29
 *
30
 * @package GravityMedia\Ssdp
31
 */
32
class Client
33
{
34
    /**
35
     * The multicast address
36
     */
37
    const MULTICAST_ADDRESS = '239.255.255.250';
38
39
    /**
40
     * The multicast port
41
     */
42
    const MULTICAST_PORT = 1900;
43
44
    /**
45
     * @var EventDispatcherInterface
46
     */
47
    protected $eventDispatcher;
48
49
    /**
50
     * @var MulticastFactory
51
     */
52
    protected $multicastFactory;
53
54
    /**
55
     * @var RequestFactory
56
     */
57
    protected $requestFactory;
58
59
    /**
60
     * Get event dispatcher
61
     *
62
     * @return EventDispatcherInterface
63
     */
64
    public function getEventDispatcher()
65
    {
66
        if (null === $this->eventDispatcher) {
67
            $this->eventDispatcher = new EventDispatcher();
68
        }
69
70
        return $this->eventDispatcher;
71
    }
72
73
    /**
74
     * Set event dispatcher
75
     *
76
     * @param EventDispatcherInterface $eventDispatcher
77
     *
78
     * @return $this
79
     */
80 2
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
81
    {
82 2
        $this->eventDispatcher = $eventDispatcher;
83
84 2
        return $this;
85
    }
86
87
    /**
88
     * Get multicast factory
89
     *
90
     * @return MulticastFactory
91
     */
92 2
    public function getMulticastFactory()
93
    {
94 2
        if (null === $this->multicastFactory) {
95
            $this->multicastFactory = new MulticastFactory();
96
        }
97
98 2
        return $this->multicastFactory;
99
    }
100
101
    /**
102
     * Set multicast factory
103
     *
104
     * @param MulticastFactory $multicastFactory
105
     *
106
     * @return $this
107
     */
108 2
    public function setMulticastFactory(MulticastFactory $multicastFactory)
109
    {
110 2
        $this->multicastFactory = $multicastFactory;
111
112 2
        return $this;
113
    }
114
115
    /**
116
     * Get request factory
117
     *
118
     * @return RequestFactory
119
     */
120 2
    public function getRequestFactory()
121
    {
122 2
        if (null === $this->requestFactory) {
123
            $this->requestFactory = new RequestFactory();
124
        }
125
126 2
        return $this->requestFactory;
127
    }
128
129
    /**
130
     * Set request factory
131
     *
132
     * @param RequestFactory $requestFactory
133
     *
134
     * @return $this
135
     */
136 2
    public function setRequestFactory(RequestFactory $requestFactory)
137
    {
138 2
        $this->requestFactory = $requestFactory;
139
140 2
        return $this;
141
    }
142
143
    /**
144
     * Send request
145
     *
146
     * @param Socket $socket
147
     * @param RequestInterface $request
148
     * @param callable $onSuccess
149
     * @param callable $onFailure
150
     *
151
     * @return boolean
152
     */
153 2
    protected function sendRequest(Socket $socket, RequestInterface $request, $onSuccess, $onFailure)
154
    {
155 2
        $data = trim(RequestSerializer::toString($request)) . "\r\n\r\n";
156
157
        try {
158 2
            $bytes = $socket->sendTo($data, 0, sprintf('%s:%s', self::MULTICAST_ADDRESS, self::MULTICAST_PORT));
159 1
        } catch (SocketException $exception) {
160
            return $onFailure($socket, $exception);
161
        }
162
163 2
        return $onSuccess($socket, $bytes);
164
    }
165
166
    /**
167
     * Receive response
168
     *
169
     * @param Socket $socket
170
     * @param callable $onSuccess
171
     * @param callable $onFailure
172
     *
173
     * @return boolean
174
     */
175 2
    protected function receiveResponse(Socket $socket, $onSuccess, $onFailure)
176
    {
177
        try {
178 2
            $message = $socket->recvFrom(1024, MSG_WAITALL, $remote);
179 1
        } catch (SocketException $exception) {
180
            return $onFailure($socket, $exception);
181
        }
182
183 2
        return $onSuccess($socket, $message, $remote);
184
    }
185
186
    /**
187
     * Send alive request
188
     *
189
     * @param AliveOptions $options
190
     *
191
     * @return boolean
192
     */
193 View Code Duplication
    public function alive(AliveOptions $options)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
    {
195
        return $this->sendRequest(
196
            $this->getMulticastFactory()->createSocket(self::MULTICAST_ADDRESS),
197
            $this->getRequestFactory()->createAliveRequest($options),
198
            function (Socket $socket) {
199
                $socket->close();
200
201
                return true;
202
            },
203
            function (Socket $socket, SocketException $exception) {
204
                $socket->close();
205
206
                $event = new DiscoverEvent();
207
                $event->setException(new DiscoverException('Error sending alive broadcast', 0, $exception));
208
                $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER_ERROR, $event);
209
210
                return false;
211
            }
212
        );
213
    }
214
215
    /**
216
     * Send byebye request
217
     *
218
     * @param ByebyeOptions $options
219
     *
220
     * @return boolean
221
     */
222 View Code Duplication
    public function byebye(ByebyeOptions $options)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
223
    {
224
        return $this->sendRequest(
225
            $this->getMulticastFactory()->createSocket(self::MULTICAST_ADDRESS),
226
            $this->getRequestFactory()->createByebyeRequest($options),
227
            function (Socket $socket) {
228
                $socket->close();
229
230
                return true;
231
            },
232
            function (Socket $socket, SocketException $exception) {
233
                $socket->close();
234
235
                $event = new DiscoverEvent();
236
                $event->setException(new DiscoverException('Error sending byebye broadcast', 0, $exception));
237
                $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER_ERROR, $event);
238
239
                return false;
240
            }
241
        );
242
    }
243
244
    /**
245
     * Send discover request
246
     *
247
     * @param DiscoverOptions $options
248
     * @param int $timeout
249
     *
250
     * @return boolean
251
     */
252 2
    public function discover(DiscoverOptions $options, $timeout = 2)
253
    {
254 2
        return $this->sendRequest(
255 2
            $this->getMulticastFactory()->createSocket(self::MULTICAST_ADDRESS, $timeout),
256 2
            $this->getRequestFactory()->createDiscoverRequest($options),
257
            function (Socket $socket) {
258
                do {
259 2
                    $continue = $this->receiveResponse(
260 1
                        $socket,
261
                        function (Socket $socket, $message, $remote) {
262 2
                            if (null === $message) {
263 2
                                return false;
264
                            }
265
266
                            $event = $this->createDiscoverEvent($message)->setRemote($remote);
267
                            $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER, $event);
268
269
                            return true;
270 2
                        },
271
                        function (Socket $socket, SocketException $exception) {
272
                            if (SOCKET_EAGAIN === $exception->getCode()) {
273
                                return false;
274
                            }
275
276
                            $exception = new DiscoverException('Error receiving discover message', 0, $exception);
277
                            $event = new DiscoverEvent();
278
                            $event->setException($exception);
279
                            $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER_ERROR, $event);
280
281
                            return false;
282 1
                        }
283 1
                    );
284
285 2
                } while ($continue);
286
287 2
                $socket->close();
288
289 2
                return true;
290 2
            },
291
            function (Socket $socket, SocketException $exception) {
292
                $socket->close();
293
294
                $event = new DiscoverEvent();
295
                $event->setException(new DiscoverException('Error sending discover broadcast', 0, $exception));
296
                $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER_ERROR, $event);
297
298
                return false;
299 1
            }
300 1
        );
301
    }
302
303
    /**
304
     * Send update request
305
     *
306
     * @param UpdateOptions $options
307
     *
308
     * @return boolean
309
     */
310 View Code Duplication
    public function update(UpdateOptions $options)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
    {
312
        return $this->sendRequest(
313
            $this->getMulticastFactory()->createSocket(self::MULTICAST_ADDRESS),
314
            $this->getRequestFactory()->createUpdateRequest($options),
315
            function (Socket $socket) {
316
                $socket->close();
317
318
                return true;
319
            },
320
            function (Socket $socket, SocketException $exception) {
321
                $socket->close();
322
323
                $event = new DiscoverEvent();
324
                $event->setException(new DiscoverException('Error sending byebye broadcast', 0, $exception));
325
                $this->getEventDispatcher()->dispatch(DiscoverEvent::EVENT_DISCOVER_ERROR, $event);
326
327
                return false;
328
            }
329
        );
330
    }
331
332
    /**
333
     * Create discover event
334
     *
335
     * @param string $message
336
     *
337
     * @return DiscoverEvent
338
     */
339
    protected function createDiscoverEvent($message)
340
    {
341
        $response = ResponseSerializer::fromString($message);
342
        $event = new DiscoverEvent();
343
344
        if ($response->hasHeader('CACHE-CONTROL')) {
345
            $value = $response->getHeaderLine('CACHE-CONTROL');
346
            $event->setLifetime(intval(substr($value, strpos($value, '=') + 1)));
347
        }
348
349
        if ($response->hasHeader('DATE')) {
350
            $event->setDate(new \DateTime($response->getHeaderLine('DATE')));
351
        }
352
353
        if ($response->hasHeader('LOCATION')) {
354
            $event->setDescriptionUrl(new Uri($response->getHeaderLine('LOCATION')));
355
        }
356
357
        if ($response->hasHeader('SERVER')) {
358
            $event->setServerString($response->getHeaderLine('SERVER'));
359
        }
360
361
        if ($response->hasHeader('ST')) {
362
            $event->setSearchTargetString($response->getHeaderLine('ST'));
363
        }
364
365
        if ($response->hasHeader('USN')) {
366
            $event->setUniqueServiceNameString($response->getHeaderLine('USN'));
367
        }
368
369
        return $event;
370
    }
371
}
372