AbstractBaseListener::isThisBot()
last analyzed

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
ccs 0
cts 0
cp 0
c 0
b 0
f 0
nc 1
1
<?php
2
3
namespace Botonomous\listener;
4
5
use Botonomous\BotonomousException;
6
use Botonomous\Config;
7
use Botonomous\Event;
8
use Botonomous\utility\RequestUtility;
9
10
abstract class AbstractBaseListener
11
{
12
    const ORIGIN_VERIFICATION_SUCCESS_KEY = 'success';
13
    const ORIGIN_VERIFICATION_MESSAGE_KEY = 'message';
14
15
    private $config;
16
    private $request;
17
    private $requestUtility;
18
19
    /**
20
     * listen.
21
     *
22
     * @throws \Exception
23
     *
24
     * @return mixed
25
     */
26 10
    public function listen()
27
    {
28
        // This is needed otherwise timeout error is displayed
29 10
        $this->respondOK();
30
31 10
        $request = $this->extractRequest();
32
33 10
        if (empty($request)) {
34
            /* @noinspection PhpInconsistentReturnPointsInspection */
35 6
            return;
36
        }
37
38 4
        $this->setRequest($request);
39
40 4
        if ($this->isThisBot() !== false) {
41
            /* @noinspection PhpInconsistentReturnPointsInspection */
42 2
            return;
43
        }
44
45 2
        return $request;
46
    }
47
48
    /**
49
     * @return mixed
50
     */
51
    abstract public function extractRequest();
52
53
    /**
54
     * @return string
55
     */
56
    abstract public function getChannelId(): string;
57
58
    /**
59
     * @param null|string $key
60
     *
61
     * @return mixed
62
     */
63 35
    public function getRequest(string $key = null)
64
    {
65 35
        if (!isset($this->request)) {
66
            // each listener has its own way of extracting the request
67 10
            $this->setRequest($this->extractRequest());
68
        }
69
70 35
        if ($key === null) {
71
            // return the entire request since key is null
72 18
            return $this->request;
73
        }
74
75 25
        if (is_array($this->request) && array_key_exists($key, $this->request)) {
76 23
            return $this->request[$key];
77
        }
78 9
    }
79
80
    /**
81
     * @param array $request
82
     */
83 45
    public function setRequest($request)
84
    {
85 45
        $this->request = $request;
86 45
    }
87
88
    /**
89
     * @return Config
90
     */
91 8
    public function getConfig(): Config
92
    {
93 8
        if (!isset($this->config)) {
94 5
            $this->setConfig(new Config());
95
        }
96
97 8
        return $this->config;
98
    }
99
100
    /**
101
     * @param Config $config
102
     */
103 12
    public function setConfig(Config $config)
104
    {
105 12
        $this->config = $config;
106 12
    }
107
108
    /**
109
     * Verify the request comes from Slack
110
     * Each listener must have have this and has got its own way to check the request.
111
     *
112
     * @throws \Exception
113
     *
114
     * @return array
115
     */
116
    abstract public function verifyOrigin();
117
118
    /**
119
     * Check if the request belongs to the bot itself.
120
     *
121
     * @throws \Exception
122
     *
123
     * @return bool
124
     */
125
    abstract public function isThisBot(): bool;
126
127
    /**
128
     * @return RequestUtility
129
     */
130 24
    public function getRequestUtility(): RequestUtility
131
    {
132 24
        if (!isset($this->requestUtility)) {
133 8
            $this->setRequestUtility((new RequestUtility()));
134
        }
135
136 24
        return $this->requestUtility;
137
    }
138
139
    /**
140
     * @param RequestUtility $requestUtility
141
     */
142 25
    public function setRequestUtility(RequestUtility $requestUtility)
143
    {
144 25
        $this->requestUtility = $requestUtility;
145 25
    }
146
147
    /**
148
     * respondOK.
149
     */
150 10
    protected function respondOK()
151
    {
152
        // check if fastcgi_finish_request is callable
153 10
        if (is_callable('fastcgi_finish_request')) {
154
            /*
155
             * http://stackoverflow.com/a/38918192
156
             * This works in Nginx but the next approach not
157
             */
158
            session_write_close();
159
            fastcgi_finish_request();
160
161
            /* @noinspection PhpInconsistentReturnPointsInspection */
162
            return;
163
        }
164
165 10
        ignore_user_abort(true);
166
167 10
        ob_start();
168 10
        header($this->getRequestUtility()->getServerProtocol().' 200 OK');
169
        // Disable compression (in case content length is compressed).
170 10
        header('Content-Encoding: none');
171 10
        header('Content-Length: '.ob_get_length());
172
173
        // Close the connection.
174 10
        header('Connection: close');
175
176 10
        ob_end_flush();
177
        // only if an output buffer is active do ob_flush
178 10
        if (ob_get_level() > 0) {
179 10
            ob_flush();
180
        }
181
182 10
        flush();
183
184
        /* @noinspection PhpInconsistentReturnPointsInspection */
185 10
    }
186
187
    /**
188
     * @throws \Exception
189
     *
190
     * @return array<string,boolean|string>
191
     */
192 5
    public function verifyRequest(): array
193
    {
194 5
        $originCheck = $this->verifyOrigin();
195 5
        if (!isset($originCheck[self::ORIGIN_VERIFICATION_SUCCESS_KEY])) {
196
            throw new BotonomousException('Success must be provided in verifyOrigin response');
197
        }
198
199 5
        if ($originCheck[self::ORIGIN_VERIFICATION_SUCCESS_KEY] !== true) {
200
            return [
201 1
                self::ORIGIN_VERIFICATION_SUCCESS_KEY => false,
202 1
                self::ORIGIN_VERIFICATION_MESSAGE_KEY => $originCheck[self::ORIGIN_VERIFICATION_MESSAGE_KEY],
203
            ];
204
        }
205
206 4
        if ($this->isThisBot() !== false) {
207
            return [
208 1
                self::ORIGIN_VERIFICATION_SUCCESS_KEY => false,
209 1
                self::ORIGIN_VERIFICATION_MESSAGE_KEY => 'Request comes from the bot',
210
            ];
211
        }
212
213 3
        return [self::ORIGIN_VERIFICATION_SUCCESS_KEY => true, self::ORIGIN_VERIFICATION_MESSAGE_KEY => 'Yay!'];
214
    }
215
216
    /**
217
     * @return string|null
218
     */
219 8
    public function determineAction()
220
    {
221 8
        $utility = $this->getRequestUtility();
222 8
        $getRequest = $utility->getGet();
223
224 8
        if (!empty($getRequest['action'])) {
225 2
            return strtolower($getRequest['action']);
226
        }
227
228 6
        $request = $utility->getPostedBody();
229
230 6
        if (isset($request['type']) && $request['type'] === 'url_verification') {
231 1
            return 'url_verification';
232
        }
233 5
    }
234
235
    /**
236
     * Return message based on the listener
237
     * If listener is event and event text is empty, fall back to request text.
238
     *
239
     * @throws \Exception
240
     *
241
     * @return mixed|string
242
     */
243 9
    public function getMessage()
244
    {
245 9
        if ($this instanceof EventListener && $this->getEvent() instanceof Event) {
246 1
            $message = $this->getEvent()->getText();
247
248 1
            if (!empty($message)) {
249 1
                return $message;
250
            }
251
        }
252
253 8
        return $this->getRequest('text');
254
    }
255
}
256