Completed
Push — master ( 4cbc31...24c6fe )
by Edgar
01:56
created

APNSNotification::__construct()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 10
cp 0
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 3
nop 3
crap 30
1
<?php
2
namespace nstdio\notymo;
3
4
use nstdio\notymo\exception\InvalidCert;
5
6
/**
7
 * Class APNSNotificationComponent
8
 */
9
class APNSNotification extends AbstractNotification
10
{
11
    /**
12
     * @var string APNS live server.
13
     */
14
    private $apnsHost = 'gateway.push.apple.com';
15
16
    /**
17
     * @var string APNS sandbox server
18
     */
19
    private $apnsSandboxHost = 'gateway.sandbox.push.apple.com';
20
21
    /**
22
     * @var int APNS server port to connect.
23
     */
24
    private $apnsPort = 2195;
25
26
    /**
27
     * @var string
28
     */
29
    private $apnsCert = 'apns-production.pem';
30
31
    /**
32
     * @var string
33
     */
34
    private $apnsSandboxCert = 'apns-dev.pem';
35
36
    /**
37
     * @var string
38
     */
39
    private $scheme = 'https';
40
41
    /**
42
     * @var bool Connect to APNS sandbox or live server.
43
     */
44
    private $live = false;
45
46
    /**
47
     * APNSNotification constructor.
48
     *
49
     * @param bool        $live
50
     * @param string|null $apnsCert
51
     * @param string|null $apnsSandboxCert
52
     *
53
     * @throws InvalidCert When cannot find one of certificate files.
54
     */
55
    public function __construct($live = false, $apnsCert = null, $apnsSandboxCert = null)
56
    {
57
        parent::__construct();
58
        $this->live = $live;
59
60
        if ($this->live && !is_readable($apnsCert)) {
61
            throw new InvalidCert("Cannot find certificate file: " . $this->apnsCert);
62
        }
63
64
        if (!$this->live && !is_readable($apnsSandboxCert)) {
65
            throw new InvalidCert("Cannot find certificate file: " . $this->apnsSandboxCert);
66
        }
67
68
        $this->apnsCert = $apnsCert;
69
        $this->apnsSandboxCert = $apnsSandboxCert;
70
    }
71
72
    /**
73
     * @throws \Exception
74
     */
75
    public function send()
76
    {
77
        if ($this->messageQueue->isEmpty()) {
78
            return;
79
        }
80
81
        $this->openConnection()
82
            ->write()
83
            ->close();
84
    }
85
86
    private function close()
87
    {
88
        $this->stream->close();
89
    }
90
91
    /**
92
     * Writes all data to the stream
93
     *
94
     * @return self
95
     */
96
    private function write()
97
    {
98
        /** @var MessageInterface $message */
99
        foreach ($this->messageQueue as $message) {
100
            $payload = $this->createPayload($message);
101
            $binMsg = $this->createBinMessage($message, $payload);
102
            $this->stream->write(CURLOPT_POSTFIELDS, $binMsg);
103
            $this->stream->read();
104
        }
105
106
        return $this;
107
    }
108
109
    /**
110
     * @param MessageInterface $message
111
     *
112
     * @return string Тhe json encoded string
113
     */
114
    final protected function createPayload(MessageInterface $message)
115
    {
116
        $payload = array();
117
        $payload['aps'] = array(
118
            'alert' => $message->getMessage(),
119
            'badge' => $message->getBadge(),
120
            'sound' => $message->getSound(),
121
        );
122
123
        /**
124
         * @var MessageInterface $value
125
         */
126
        foreach ($message->getCustomData() as $key => $value) {
127
            $payload[$key] = $value;
128
        }
129
130
131
        return json_encode($payload);
132
    }
133
134
    /**
135
     * @param $message
136
     * @param $payload
137
     *
138
     * @return string
139
     */
140
    private function createBinMessage(MessageInterface $message, $payload)
141
    {
142
        $binMsg = '';
143
        if ($message->isMultiple()) {
144
            foreach ($message->getToken() as $token) {
145
                $binMsg .= $this->buildBinMessage($token, $payload);
146
            }
147
        } else {
148
            $binMsg = $this->buildBinMessage($message->getToken(), $payload);
149
        }
150
151
        return $binMsg;
152
    }
153
154
    /**
155
     * @param $token
156
     * @param $payload
157
     *
158
     * @return string
159
     *
160
     */
161
    private function buildBinMessage($token, $payload)
162
    {
163
        $token = $this->removeTags($token);
164
165
        return chr(0)
166
        . chr(0)
167
        . chr(32)
168
        . pack('H*', str_replace(' ', '', $token))
169
        . chr(0)
170
        . chr(strlen($payload))
171
        . $payload;
172
    }
173
174
    /**
175
     * @param $deviceToken
176
     *
177
     * @return mixed
178
     */
179
    private function removeTags($deviceToken)
180
    {
181
        return str_replace(array('<', '>'), '', $deviceToken);
182
    }
183
184
    protected function getConnectionParams()
185
    {
186
        return array(
187
            CURLOPT_URL            => $this->getRemoteSocketAddress(),
188
            CURLOPT_RETURNTRANSFER => true,
189
            CURLOPT_FOLLOWLOCATION => true,
190
            CURLOPT_HEADER         => true,
191
            CURLOPT_SSL_VERIFYPEER => true,
192
            CURLOPT_SSLCERT        => $this->live ? $this->apnsCert : $this->apnsSandboxCert,
193
            CURLOPT_POST           => true,
194
        );
195
    }
196
197
    /**
198
     * @return string Full qualified url address of APNS server.
199
     */
200
    private function getRemoteSocketAddress()
201
    {
202
        return sprintf("%s://%s:%d", $this->scheme, $this->live ? $this->apnsHost : $this->apnsSandboxHost, $this->apnsPort);
203
    }
204
}