1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <contact@terryl.in>
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 <contact@terryl.in>
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 Shieldon\Firewall\Container;
29
use Shieldon\Event\Event;
30
use function Shieldon\Firewall\get_response;
31
use function Shieldon\Firewall\get_request;
32
use function Shieldon\Firewall\get_session_instance;
33
use function Shieldon\Firewall\__;
34
use InvalidArgumentException;
35
use RuntimeException;
36
use function array_keys;
37
use function define;
38
use function defined;
39
use function is_dir;
40
use function ob_end_clean;
41
use function ob_get_contents;
42
use function ob_start;
43
use function file_exists;
44
use function sprintf;
45

46
/*
47
 * The template-related functions.
48
 */
49
trait TemplateTrait
50
{
51
    /**
52
     *   Public methods       | Desctiotion
53
     *  ----------------------|---------------------------------------------
54
     *   respond              | Respond the result.
55
     *   setTemplateDirectory | Set the frontend template directory.
56
     *   getJavascript        | Print a JavaScript snippet in the pages.
57
     *  ----------------------|---------------------------------------------
58
     */
59

60
    /**
61
     * The directory in where the frontend template files are placed.
62
     *
63
     * @var string
64
     */
65
    protected $templateDirectory = '';
66

67
    /**
68
     * Custom dialog UI settings.
69
     *
70
     * @var array
71
     */
72
    protected $dialog = [];
73

74
    /**
75
     * Get current visior's path.
76
     *
77
     * @return string
78
     */
79
    abstract public function getCurrentUrl(): string;
80

81
    /**
82
     * Customize the dialog UI.
83
     * 
84
     * @param array $settings The dialog UI settings.
85
     *
86
     * @return void
87
     */
88 3
    public function setDialog(array $settings): void
89
    {
90 3
        $this->dialog = $settings;
91
    }
92

93
    /**
94
     * Respond the result.
95
     *
96
     * @return ResponseInterface
97
     */
98 3
    public function respond(): ResponseInterface
99
    {
100 3
        $response = get_response();
101

102
        $httpStatusCodes = [
103 2
            Kernel::RESPONSE_TEMPORARILY_DENY => [
104 1
                'type' => 'captcha',
105
                'code' => Kernel::HTTP_STATUS_FORBIDDEN,
106
            ],
107

108
            Kernel::RESPONSE_LIMIT_SESSION => [
109
                'type' => 'session_limitation',
110
                'code' => Kernel::HTTP_STATUS_TOO_MANY_REQUESTS,
111
            ],
112

113
            Kernel::RESPONSE_DENY => [
114
                'type' => 'rejection',
115
                'code' => Kernel::HTTP_STATUS_BAD_REQUEST,
116
            ],
117
        ];
118

119
        // Nothing happened. Return.
120 3
        if (empty($httpStatusCodes[$this->result])) {
121 3
            return $response;
122
        }
123

124 3
        $type = $httpStatusCodes[$this->result]['type'];
125 3
        $statusCode = $httpStatusCodes[$this->result]['code'];
126

127 3
        $viewPath = $this->getTemplate($type);
128

129
        // The language of output UI. It is used on views.
130 3
        $langCode = get_session_instance()->get('shieldon_ui_lang') ?? 'en';
131

132 3
        $onlineinfo = [];
133 3
        $onlineinfo['queue'] = $this->sessionStatus['queue'];
134 3
        $onlineinfo['count'] = $this->sessionStatus['count'];
135 3
        $onlineinfo['period'] = $this->sessionLimit['period'];
136

137 3
        $dialoguserinfo = [];
138 3
        $dialoguserinfo['ip'] = $this->ip;
139 3
        $dialoguserinfo['rdns'] = $this->rdns;
140 3
        $dialoguserinfo['user_agent'] = get_request()->getHeaderLine('user-agent');
141

142
        // Captcha form
143 3
        $form = $this->getCurrentUrl();
144 3
        $captchas = $this->captcha;
145

146
        // Check and confirm the UI settings.
147 3
        $ui = $this->confirmUiSettings();
148 3
        $uiInfo = $this->confirmUiInfoSettings($statusCode);
149

150 3
        $css = include $this->getTemplate('css/default');
151

152
        /**
153
         * Hook - dialog_output
154
         */
155 3
        Event::doDispatch('dialog_output');
156

157 3
        $performanceReport = $this->displayPerformanceReport();
158

159 3
        ob_start();
160 3
        include $viewPath;
161 3
        $output = ob_get_contents();
162 3
        ob_end_clean();
163

164
        // Remove unused variable notices generated from PHP intelephense.
165 3
        unset($css, $ui, $form, $captchas, $langCode, $performanceReport, $uiInfo);
166

167 3
        $stream = HttpFactory::createStream();
168 3
        $stream->write($output);
169 3
        $stream->rewind();
170

171
        return $response
172 3
            ->withHeader('X-Protected-By', 'shieldon.io')
173 3
            ->withBody($stream)
174 3
            ->withStatus($statusCode);
175
    }
176

177
    /**
178
     * Print a JavaScript snippet in your webpages.
179
     * 
180
     * This snippet generate cookie on client's browser,then we check the 
181
     * cookie to identify the client is a rebot or not.
182
     *
183
     * @return string
184
     */
185 3
    public function getJavascript(): string
186
    {
187 3
        $tmpCookieName = $this->properties['cookie_name'];
188 3
        $tmpCookieDomain = $this->properties['cookie_domain'];
189

190 3
        if (empty($tmpCookieDomain) && get_request()->getHeaderLine('host')) {
191 3
            $tmpCookieDomain = get_request()->getHeaderLine('host');
192
        }
193

194 3
        $tmpCookieValue = $this->properties['cookie_value'];
195

196
        $jsString = '
197
            <script>
198
                var d = new Date();
199
                d.setTime(d.getTime()+(60*60*24*30));
200 3
                document.cookie = "' . $tmpCookieName . '=' . $tmpCookieValue . ';domain=.' . $tmpCookieDomain . ';expires="+d.toUTCString();
201
            </script>
202
        ';
203

204 3
        return $jsString;
205
    }
206

207
    /**
208
     * Set the frontend template directory.
209
     *
210
     * @param string $directory The directory in where the template files are placed.
211
     *
212
     * @return void
213
     */
214 3
    public function setTemplateDirectory(string $directory): void
215
    {
216 3
        if (!is_dir($directory)) {
217 3
            throw new InvalidArgumentException(
218 3
                'The template directory does not exist.'
219
            );
220
        }
221 3
        $this->templateDirectory = $directory;
222
    }
223

224
    /**
225
     * Get a template PHP file.
226
     *
227
     * @param string $type The template type.
228
     *
229
     * @return string
230
     */
231 3
    protected function getTemplate(string $type): string
232
    {
233 3
        $directory = Kernel::KERNEL_DIR . '/../../templates/frontend';
234

235 3
        if (!empty($this->templateDirectory)) {
236 3
            $directory = $this->templateDirectory;
237
        }
238

239 3
        $path = $directory . '/' . $type . '.php';
240

241 3
        if (!file_exists($path)) {
242 3
            throw new RuntimeException(
243 3
                sprintf(
244 3
                    'The templeate file is missing. (%s)',
245 3
                    $path
246
                )
247
            );
248
        }
249

250 3
        return $path;
251
    }
252

253
    /**
254
     * Count the performance statistics.
255
     *
256
     * @return array
257
     */
258 3
    protected function getPerformanceStats(): array
259
    {
260 3
        $statStart = Container::get('shieldon_start');
261 3
        $statEnd = Container::get('shieldon_end');
262

263 3
        $startTimeArr = explode(' ',$statStart['time']);
264 3
        $endTimeArr = explode(' ',$statStart['time']);
265

266 3
        $timeDifference = ($endTimeArr[1] - $startTimeArr[1]) + ($endTimeArr[0] - $startTimeArr[0]);
267 3
        $memoryDifference = round(($statEnd['memory'] - $statStart['memory']) / 1024, 2); // KB
268

269
        $data = [
270 3
            'time' => $timeDifference,
271 3
            'memory' => $memoryDifference,
272
        ];
273

274 3
        return $data;
275
    }
276

277
    /**
278
     * Display the HTML of the performance report.
279
     *
280
     * @return string
281
     */
282 3
    protected function displayPerformanceReport(): string
283
    {
284 3
        if (!Container::get('shieldon_start')) {
285 3
            return '';
286
        }
287

288 3
        $html = '';
289

290 3
        $performance = $this->getPerformanceStats();
291

292 3
        if ($performance['time'] < 0.001) {
293 3
            $performance['time'] = 'fewer than 0.001';
294
        }
295

296 3
        if (isset($performance['time'])) {
297 3
            $html .= '<div class="performance-report">';
298 3
            $html .= 'Memory consumed: <strong>' . $performance['memory'] . '</strong> KB / ';
299 3
            $html .= 'Execution:  <strong>' . $performance['time'] . ' </strong> seconds.';
300 3
            $html .= '</div>';
301
        }
302

303 3
        return $html;
304
    }
305

306

307
    /**
308
     * Confirm the UI settings.
309
     *
310
     * @return array
311
     */
312 3
    private function confirmUiSettings(): array
313
    {
314 3
        if (!defined('SHIELDON_VIEW')) {
315 3
            define('SHIELDON_VIEW', true);
316
        }
317

318
        $ui = [
319 3
            'background_image' => '',
320
            'bg_color'         => '#ffffff',
321
            'header_bg_color'  => '#212531',
322
            'header_color'     => '#ffffff',
323
            'shadow_opacity'   => '0.2',
324
        ];
325

326 3
        foreach (array_keys($ui) as $key) {
327 3
            if (!empty($this->dialog[$key])) {
328 3
                $ui[$key] = $this->dialog[$key];
329
            }
330
        }
331

332 3
        return $ui;
333
    }
334

335
    /**
336
     * Confirm UI information settings.
337
     * 
338
     * @param int $statusCode HTTP status code.
339
     *
340
     * @return array
341
     */
342 3
    private function confirmUiInfoSettings(int $statusCode): array
343
    {
344 3
        $uiInfo = [];
345

346 3
        $reasonCode = $this->reason;
347

348 3
        $uiInfo['http_status_code'] = $statusCode;
349 3
        $uiInfo['reason_code']      = $reasonCode;
350 3
        $uiInfo['reason_text']      = __('core', 'messenger_text_reason_code_' . $reasonCode);
351

352 3
        $uiInfo['is_display_online_user_amount']  = $this->properties['display_online_info'];
353 3
        $uiInfo['is_display_user_information']    = $this->properties['display_user_info'];
354 3
        $uiInfo['is_display_display_http_code']   = $this->properties['display_http_code'];
355 3
        $uiInfo['is_display_display_reason_code'] = $this->properties['display_reason_code'];
356 3
        $uiInfo['is_display_display_reason_text'] = $this->properties['display_reason_text'];
357

358 3
        return $uiInfo;
359
    }
360
}

Read our documentation on viewing source code .

Loading