Completed
Push — master ( edcf20...3ec6c0 )
by Marcel
03:05 queued 01:22
created

src/WebSockets/Channels/Channel.php (5 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 BeyondCode\LaravelWebSockets\WebSockets\Channels;
4
5
use stdClass;
6
use Illuminate\Support\Str;
7
use Ratchet\ConnectionInterface;
8
use BeyondCode\LaravelWebSockets\Dashboard\DashboardLogger;
9
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\InvalidSignature;
10
11
class Channel
12
{
13
    /** @var string */
14
    protected $channelName;
15
16
    /** @var \Ratchet\ConnectionInterface[] */
17
    protected $subscribedConnections = [];
18
19
    public function __construct(string $channelName)
20
    {
21
        $this->channelName = $channelName;
22
    }
23
24
    public function hasConnections(): bool
25
    {
26
        return count($this->subscribedConnections) > 0;
27
    }
28
29
    public function getSubscribedConnections(): array
30
    {
31
        return $this->subscribedConnections;
32
    }
33
34
    protected function verifySignature(ConnectionInterface $connection, stdClass $payload)
35
    {
36
        $signature = "{$connection->socketId}:{$this->channelName}";
0 ignored issues
show
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
37
38
        if (isset($payload->channel_data)) {
39
            $signature .= ":{$payload->channel_data}";
40
        }
41
42
        if (Str::after($payload->auth, ':') !== hash_hmac('sha256', $signature, $connection->app->secret)) {
0 ignored issues
show
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
43
            throw new InvalidSignature();
44
        }
45
    }
46
47
    /*
48
     * @link https://pusher.com/docs/pusher_protocol#presence-channel-events
49
     */
50
    public function subscribe(ConnectionInterface $connection, stdClass $payload)
51
    {
52
        $this->saveConnection($connection);
53
54
        $connection->send(json_encode([
55
            'event' => 'pusher_internal:subscription_succeeded',
56
            'channel' => $this->channelName,
57
        ]));
58
    }
59
60
    public function unsubscribe(ConnectionInterface $connection)
61
    {
62
        unset($this->subscribedConnections[$connection->socketId]);
63
64
        if (! $this->hasConnections()) {
65
            DashboardLogger::vacated($connection, $this->channelName);
66
        }
67
    }
68
69
    protected function saveConnection(ConnectionInterface $connection)
70
    {
71
        $hadConnectionsPreviously = $this->hasConnections();
72
73
        $this->subscribedConnections[$connection->socketId] = $connection;
0 ignored issues
show
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
74
75
        if (! $hadConnectionsPreviously) {
76
            DashboardLogger::occupied($connection, $this->channelName);
77
        }
78
79
        DashboardLogger::subscribed($connection, $this->channelName);
80
    }
81
82
    public function broadcast($payload)
83
    {
84
        foreach ($this->subscribedConnections as $connection) {
85
            $connection->send(json_encode($payload));
86
        }
87
    }
88
89
    public function broadcastToOthers(ConnectionInterface $connection, $payload)
90
    {
91
        $this->broadcastToEveryoneExcept($payload, $connection->socketId);
0 ignored issues
show
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
92
    }
93
94
    public function broadcastToEveryoneExcept($payload, ?string $socketId = null)
95
    {
96
        if (is_null($socketId)) {
97
            return $this->broadcast($payload);
98
        }
99
100
        foreach ($this->subscribedConnections as $connection) {
101
            if ($connection->socketId !== $socketId) {
0 ignored issues
show
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
102
                $connection->send(json_encode($payload));
103
            }
104
        }
105
    }
106
107
    public function toArray(): array
108
    {
109
        return [
110
            'occupied' => count($this->subscribedConnections) > 0,
111
            'subscription_count' => count($this->subscribedConnections),
112
        ];
113
    }
114
}
115