Completed
Push — master ( 5f4df6...b69829 )
by Benjamin
01:49
created

StreamSocketClient   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 98.08%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 0
dl 0
loc 239
ccs 51
cts 52
cp 0.9808
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A __destruct() 0 4 1
B initSocket() 0 30 3
A write() 0 17 3
A read() 0 4 1
A close() 0 9 2
A getConnectTimeout() 0 4 1
A setConnectTimeout() 0 4 1
B buildSocket() 0 36 3
A getSocket() 0 9 2
1
<?php
2
3
/*
4
 * This file is part of the php-gelf package.
5
 *
6
 * (c) Benjamin Zikarsky <http://benjamin-zikarsky.de>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Gelf\Transport;
13
14
use RuntimeException;
15
16
/**
17
 * StreamSocketClient is a very simple OO-Wrapper around the PHP
18
 * stream_socket-library and some specific stream-functions like
19
 * fwrite, etc.
20
 *
21
 * @author Benjamin Zikarsky <[email protected]>
22
 */
23
class StreamSocketClient
24
{
25
    /**
26
     * @deprecated deprecated since v1.4.0
27
     */
28
    const SOCKET_TIMEOUT = 30;
29
30
    /**
31
     * @var string
32
     */
33
    protected $host;
34
35
    /**
36
     * @var integer
37
     */
38
    protected $port;
39
40
    /**
41
     * @var string
42
     */
43
    protected $scheme;
44
45
    /**
46
     * @var array
47
     */
48
    protected $context;
49
50
    /**
51
     * @var resource
52
     */
53
    protected $socket;
54
55
    /**
56
     * @var int
57
     */
58
    protected $connectTimeout = self::SOCKET_TIMEOUT;
59
60
    /**
61
     * @param string  $scheme
62
     * @param string  $host
63
     * @param integer $port
64
     * @param array   $context
65
     */
66 41
    public function __construct($scheme, $host, $port, array $context = array())
67
    {
68 41
        $this->scheme = $scheme;
69 41
        $this->host = $host;
70 41
        $this->port = $port;
71 41
        $this->context = $context;
72 41
    }
73
74
    /**
75
     * Destructor, closes socket if possible
76
     */
77 41
    public function __destruct()
78
    {
79 41
        $this->close();
80 41
    }
81
82
    /**
83
     * Initializes socket-client
84
     *
85
     * @deprecated deprecated since v1.4.0
86
     *
87
     * @param string  $scheme  like "udp" or "tcp"
88
     * @param string  $host
89
     * @param integer $port
90
     * @param array   $context
91
     *
92
     * @return resource
93
     *
94
     * @throws RuntimeException on connection-failure
95
     */
96
    protected static function initSocket($scheme, $host, $port, array $context)
97
    {
98
        $socketDescriptor = sprintf("%s://%s:%d", $scheme, $host, $port);
99
        $socket = @stream_socket_client(
100
            $socketDescriptor,
101
            $errNo,
102
            $errStr,
103
            static::SOCKET_TIMEOUT,
104
            \STREAM_CLIENT_CONNECT,
105
            stream_context_create($context)
106
        );
107
108
        if ($socket === false) {
109
            throw new RuntimeException(
110
                sprintf(
111
                    "Failed to create socket-client for %s: %s (%s)",
112
                    $socketDescriptor,
113
                    $errStr,
114
                    $errNo
115
                )
116
            );
117
        }
118
119
        // set non-blocking for UDP
120
        if (strcasecmp("udp", $scheme) == 0) {
121
            stream_set_blocking($socket, 0);
122
        }
123
124
        return $socket;
125
    }
126
127
128
    /**
129
     * Internal function mimicking the behaviour of static::initSocket
130
     * which will get new functionality instead of the deprecated
131
     * "factory"
132
     *
133
     * @return resource
134
     *
135
     * @throws RuntimeException on connection-failure
136
     */
137 14
    private function buildSocket()
138
    {
139 14
        $socketDescriptor = sprintf(
140 14
            "%s://%s:%d",
141 14
            $this->scheme,
142 14
            $this->host,
143 14
            $this->port
144
        );
145
146 14
        $socket = @stream_socket_client(
147
            $socketDescriptor,
148
            $errNo,
149
            $errStr,
150 14
            $this->connectTimeout,
151 14
            \STREAM_CLIENT_CONNECT,
152 14
            stream_context_create($this->context)
153
        );
154
155 14
        if ($socket === false) {
156 1
            throw new RuntimeException(
157
                sprintf(
158 1
                    "Failed to create socket-client for %s: %s (%s)",
159
                    $socketDescriptor,
160
                    $errStr,
161
                    $errNo
162
                )
163
            );
164
        }
165
166
        // set non-blocking for UDP
167 13
        if (strcasecmp("udp", $this->scheme) == 0) {
168 3
            stream_set_blocking($socket, 0);
169
        }
170
171 13
        return $socket;
172
    }
173
174
    /**
175
     * Returns raw-socket-resource
176
     *
177
     * @return resource
178
     */
179 14
    public function getSocket()
180
    {
181
        // lazy initializing of socket-descriptor
182 14
        if (!$this->socket) {
183 14
            $this->socket = $this->buildSocket();
184
        }
185
186 13
        return $this->socket;
187
    }
188
189
    /**
190
     * Writes a given string to the socket and returns the
191
     * number of written bytes
192
     *
193
     * @param string $buffer
194
     *
195
     * @return int
196
     *
197
     * @throws RuntimeException on write-failure
198
     */
199 8
    public function write($buffer)
200
    {
201 8
        $buffer = (string) $buffer;
202 8
        $socket = $this->getSocket();
203 8
        $byteCount = @fwrite($socket, $buffer);
204 8
        $bufLen = strlen($buffer);
205
206 8
        if ($byteCount === false) {
207
            throw new \RuntimeException("Failed to write to socket");
208
        }
209
210 8
        if ($byteCount !== $bufLen) {
211 1
            throw new \RuntimeException("Incomplete write: Only $byteCount of $bufLen written");
212
        }
213
214 8
        return $byteCount;
215
    }
216
217
    /**
218
     * Reads a given number of bytes from the socket
219
     *
220
     * @param integer $byteCount
221
     *
222
     * @return string
223
     */
224 2
    public function read($byteCount)
225
    {
226 2
        return fread($this->getSocket(), $byteCount);
227
    }
228
229
    /**
230
     * Closes underlying socket explicitly
231
     */
232 41
    public function close()
233
    {
234 41
        if (!is_resource($this->socket)) {
235 29
            return;
236
        }
237
238 13
        fclose($this->socket);
239 13
        $this->socket = null;
240 13
    }
241
242
    /**
243
     * Returns the current connect-timeout
244
     *
245
     * @return int
246
     */
247 1
    public function getConnectTimeout()
248
    {
249 1
        return $this->connectTimeout;
250
    }
251
252
    /**
253
     * Sets the connect-timeout
254
     *
255
     * @param int $timeout
256
     */
257 1
    public function setConnectTimeout($timeout)
258
    {
259 1
        $this->connectTimeout = $timeout;
260 1
    }
261
}
262