Passed
Push — 2.x ( 4bb95a...adaf26 )
by Terry
01:49
created

TemplateTrait::respond()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 69
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 41
nc 2
nop 0
dl 0
loc 69
rs 9.264
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 * 
10
 * php version 7.1.0
11
 * 
12
 * @category  Web-security
13
 * @package   Shieldon
14
 * @author    Terry Lin <[email protected]>
15
 * @copyright 2019 terrylinooo
16
 * @license   https://github.com/terrylinooo/shieldon/blob/2.x/LICENSE MIT
17
 * @link      https://github.com/terrylinooo/shieldon
18
 * @see       https://shieldon.io
19
 */
20
21
declare(strict_types=1);
22
23
namespace Shieldon\Firewall\Kernel;
24
25
use Psr\Http\Message\ResponseInterface;
26
use Shieldon\Firewall\Kernel;
27
use Shieldon\Firewall\HttpFactory;
28
use function Shieldon\Firewall\get_response;
29
use function Shieldon\Firewall\get_request;
30
use function Shieldon\Firewall\get_session;
31
32
use InvalidArgumentException;
33
use function array_keys;
34
use function define;
35
use function defined;
36
use function is_dir;
37
use function ob_end_clean;
38
use function ob_get_contents;
39
use function ob_start;
40
41
/*
42
 * The template-related functions.
43
 */
44
trait TemplateTrait
45
{
46
    /**
47
     * Custom dialog UI settings.
48
     *
49
     * @var array
50
     */
51
    protected $dialog = [];
52
53
    /**
54
     *   Public methods       | Desctiotion
55
     *  ----------------------|---------------------------------------------
56
     *   setDialog            | Customize the dialog UI.
57
     *   respond              | Respond the result.
58
     *   setTemplateDirectory | Set the frontend template directory.
59
     *   getJavascript        | Print a JavaScript snippet in the pages.
60
     *  ----------------------|---------------------------------------------
61
     */
62
63
    /**
64
     * Get current visior's path.
65
     *
66
     * @return string
67
     */
68
    abstract public function getCurrentUrl(): string;
69
70
    /**
71
     * Customize the dialog UI.
72
     * 
73
     * @param array $settings The dialog UI settings.
74
     *
75
     * @return void
76
     */
77
    public function setDialog(array $settings): void
78
    {
79
        $this->dialog = $settings;
80
    }
81
82
    /**
83
     * Respond the result.
84
     *
85
     * @return ResponseInterface
86
     */
87
    public function respond(): ResponseInterface
88
    {
89
        $response = get_response();
90
91
        $httpStatusCodes = [
92
            kernel::RESPONSE_TEMPORARILY_DENY => [
93
                'type' => 'captcha',
94
                'code' => kernel::HTTP_STATUS_FORBIDDEN,
95
            ],
96
97
            kernel::RESPONSE_LIMIT_SESSION => [
98
                'type' => 'session_limitation',
99
                'code' => kernel::HTTP_STATUS_TOO_MANY_REQUESTS,
100
            ],
101
102
            kernel::RESPONSE_DENY => [
103
                'type' => 'rejection',
104
                'code' => kernel::HTTP_STATUS_BAD_REQUEST,
105
            ],
106
        ];
107
108
        // Nothing happened. Return.
109
        if (empty($httpStatusCodes[$this->result])) {
110
            return $response;
111
        }
112
113
        $type = $httpStatusCodes[$this->result]['type'];
114
        $statusCode = $httpStatusCodes[$this->result]['code'];
115
116
        $viewPath = $this->getTemplate($type);
117
118
        // The language of output UI. It is used on views.
119
        $langCode = get_session()->get('shieldon_ui_lang') ?? 'en';
120
121
        $onlineinfo = [];
122
        $onlineinfo['queue'] = $this->sessionStatus['queue'];
123
        $onlineinfo['count'] = $this->sessionStatus['count'];
124
        $onlineinfo['period'] = $this->sessionLimit['period'];
125
126
        $dialoguserinfo = [];
127
        $dialoguserinfo['ip'] = $this->ip;
128
        $dialoguserinfo['rdns'] = $this->rdns;
129
        $dialoguserinfo['user_agent'] = get_request()->getHeaderLine('user-agent');
130
131
        // Captcha form
132
        $form = $this->getCurrentUrl();
133
        $captchas = $this->captcha;
134
135
        // Check and confirm the UI settings.
136
        $ui = $this->confirmUiSettings();
137
138
        $css = include $this->getTemplate('css/default');
139
140
        ob_start();
141
        include $viewPath;
142
        $output = ob_get_contents();
143
        ob_end_clean();
144
145
        // Remove unused variable notices generated from PHP intelephense.
146
        unset($css, $ui, $form, $captchas, $langCode);
147
148
        $stream = HttpFactory::createStream();
149
        $stream->write($output);
150
        $stream->rewind();
151
152
        return $response
153
            ->withHeader('X-Protected-By', 'shieldon.io')
154
            ->withBody($stream)
155
            ->withStatus($statusCode);
156
    }
157
158
    /**
159
     * Confirm the UI settings.
160
     *
161
     * @return array
162
     */
163
    private function confirmUiSettings(): array
164
    {
165
        if (!defined('SHIELDON_VIEW')) {
166
            define('SHIELDON_VIEW', true);
167
        }
168
169
        $ui = [
170
            'background_image' => '',
171
            'bg_color'         => '#ffffff',
172
            'header_bg_color'  => '#212531',
173
            'header_color'     => '#ffffff',
174
            'shadow_opacity'   => '0.2',
175
        ];
176
177
        foreach (array_keys($ui) as $key) {
178
            if (!empty($this->dialog[$key])) {
179
                $ui[$key] = $this->dialog[$key];
180
            }
181
        }
182
183
        $ui['is_display_online_info'] = false;
184
        $ui['is_display_user_info'] = false;
185
186
        // Show online session count. It is used on views.
187
        if (!empty($this->properties['display_online_info'])) {
188
            $ui['is_display_online_info'] = true;
189
        }
190
191
        // Show user information such as IP, user-agent, device name.
192
        if (!empty($this->properties['display_user_info'])) {
193
            $ui['is_display_user_info'] = true;
194
        }
195
196
        return $ui;
197
    }
198
199
    /**
200
     * Print a JavaScript snippet in your webpages.
201
     * 
202
     * This snippet generate cookie on client's browser,then we check the 
203
     * cookie to identify the client is a rebot or not.
204
     *
205
     * @return string
206
     */
207
    public function getJavascript(): string
208
    {
209
        $tmpCookieName = $this->properties['cookie_name'];
210
        $tmpCookieDomain = $this->properties['cookie_domain'];
211
212
        if (empty($tmpCookieDomain) && get_request()->getHeaderLine('host')) {
213
            $tmpCookieDomain = get_request()->getHeaderLine('host');
214
        }
215
216
        $tmpCookieValue = $this->properties['cookie_value'];
217
218
        $jsString = '
219
            <script>
220
                var d = new Date();
221
                d.setTime(d.getTime()+(60*60*24*30));
222
                document.cookie = "' . $tmpCookieName . '=' . $tmpCookieValue . ';domain=.' . $tmpCookieDomain . ';expires="+d.toUTCString();
223
            </script>
224
        ';
225
226
        return $jsString;
227
    }
228
229
    /**
230
     * Set the frontend template directory.
231
     *
232
     * @param string $directory The directory in where the template files are placed.
233
     *
234
     * @return void
235
     */
236
    public function setTemplateDirectory(string $directory): void
237
    {
238
        if (!is_dir($directory)) {
239
            throw new InvalidArgumentException(
240
                'The template directory does not exist.'
241
            );
242
        }
243
        $this->templateDirectory = $directory;
0 ignored issues
show
Bug Best Practice introduced by
The property templateDirectory does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
244
    }
245
246
    /**
247
     * Get a template PHP file.
248
     *
249
     * @param string $type The template type.
250
     *
251
     * @return string
252
     */
253
    protected function getTemplate(string $type): string
254
    {
255
        $directory = self::KERNEL_DIR . '/../../templates/frontend';
0 ignored issues
show
Bug introduced by
The constant Shieldon\Firewall\Kernel\TemplateTrait::KERNEL_DIR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
256
257
        if (!empty($this->templateDirectory)) {
258
            $directory = $this->templateDirectory;
259
        }
260
261
        $path = $directory . '/' . $type . '.php';
262
263
        if (!file_exists($path)) {
264
            throw new RuntimeException(
0 ignored issues
show
Bug introduced by
The type Shieldon\Firewall\Kernel\RuntimeException was not found. Did you mean RuntimeException? If so, make sure to prefix the type with \.
Loading history...
265
                sprintf(
266
                    'The templeate file is missing. (%s)',
267
                    $path
268
                )
269
            );
270
        }
271
272
        return $path;
273
    }
274
}
275