Passed
Branch master (2fcc75)
by Paul
11:46
created

Router::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 2
Metric Value
cc 1
eloc 3
c 3
b 0
f 2
nc 1
nop 0
dl 0
loc 5
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
namespace GeminiLabs\SiteReviews;
4
5
use GeminiLabs\SiteReviews\Helpers\Arr;
6
use GeminiLabs\SiteReviews\Modules\Notice;
7
8
class Router
9
{
10
    /**
11
     * @var array
12
     */
13
    protected $unguardedActions = [];
14
15
    public function __construct()
16
    {
17
        $this->unguardedActions = apply_filters('site-reviews/router/unguarded-actions', [
18
            'dismiss-notice',
19
            'fetch-paged-reviews',
20
        ]);
21
    }
22
23
    /**
24
     * @return void
25
     */
26 1
    public function routeAdminPostRequest()
27
    {
28 1
        $request = $this->getRequest();
29 1
        if (!$this->isValidPostRequest($request)) {
30 1
            return;
31
        }
32
        check_admin_referer($request['_action']);
33
        $this->routeRequest('admin', $request['_action'], $request);
34
    }
35
36
    /**
37
     * @return void
38
     */
39 1
    public function routeAjaxRequest()
40
    {
41 1
        $request = $this->getRequest();
42 1
        $this->checkAjaxRequest($request);
43 1
        $this->checkAjaxNonce($request);
44 1
        $this->routeRequest('ajax', $request['_action'], $request);
45
        wp_die();
46
    }
47
48
    /**
49
     * @return void
50
     */
51
    public function routePublicPostRequest()
52
    {
53
        if (is_admin()) {
54
            return;
55
        }
56
        $request = $this->getRequest();
57
        if (!$this->isValidPostRequest($request)) {
58
            return;
59
        }
60
        if (!$this->isValidPublicNonce($request)) {
61
            return;
62
        }
63
        $this->routeRequest('public', $request['_action'], $request);
64
    }
65
66
    /**
67
     * @return void
68
     */
69 1
    protected function checkAjaxNonce(array $request)
70
    {
71 1
        if (!is_user_logged_in() || in_array(Arr::get($request, '_action'), $this->unguardedActions)) {
72 1
            return;
73
        }
74
        if (!isset($request['_nonce'])) {
75
            $this->sendAjaxError('request is missing a nonce', $request);
76
        }
77
        if (!wp_verify_nonce($request['_nonce'], $request['_action'])) {
78
            $this->sendAjaxError('request failed the nonce check', $request, 403);
79
        }
80
    }
81
82
    /**
83
     * @return void
84
     */
85 1
    protected function checkAjaxRequest(array $request)
86
    {
87 1
        if (!isset($request['_action'])) {
88
            $this->sendAjaxError('request must include an action', $request);
89
        }
90 1
        if (empty($request['_ajax_request'])) {
91
            $this->sendAjaxError('request is invalid', $request);
92
        }
93 1
    }
94
95
    /**
96
     * All ajax requests in the plugin are triggered by a single action hook: glsr_action,
97
     * while each ajax route is determined by $_POST[request][_action].
98
     * @return array
99
     */
100 1
    protected function getRequest()
101
    {
102 1
        $request = Helper::filterInputArray(Application::ID);
103 1
        if (Helper::filterInput('action') == Application::PREFIX.'action') {
104 1
            $request['_ajax_request'] = true;
105
        }
106 1
        if ('submit-review' == Helper::filterInput('_action', $request)) {
107 1
            $request['_recaptcha-token'] = Helper::filterInput('g-recaptcha-response');
108
        }
109 1
        return $request;
110
    }
111
112
    /**
113
     * @return bool
114
     */
115 1
    protected function isValidPostRequest(array $request = [])
116
    {
117 1
        return !empty($request['_action']) && empty($request['_ajax_request']);
118
    }
119
120
    /**
121
     * @return bool
122
     */
123
    protected function isValidPublicNonce(array $request)
124
    {
125
        if (is_user_logged_in() && !wp_verify_nonce($request['_nonce'], $request['_action'])) {
126
            glsr_log()->error('nonce check failed for public request')->debug($request);
127
            return false;
128
        }
129
        return true;
130
    }
131
132
    /**
133
     * @param string $type
134
     * @param string $action
135
     * @return void
136
     */
137 1
    protected function routeRequest($type, $action, array $request = [])
138
    {
139 1
        $actionHook = 'site-reviews/route/'.$type.'/request';
140 1
        $controller = glsr(Helper::buildClassName($type.'-controller', 'Controllers'));
141 1
        $method = Helper::buildMethodName($action, 'router');
142 1
        $request = apply_filters('site-reviews/route/request', $request, $action, $type);
143 1
        do_action($actionHook, $action, $request);
144 1
        if (is_callable([$controller, $method])) {
145 1
            call_user_func([$controller, $method], $request);
146
            return;
147
        }
148
        if (0 === did_action($actionHook)) {
149
            glsr_log('Unknown '.$type.' router request: '.$action);
150
        }
151
    }
152
153
    /**
154
     * @param string $error
155
     * @param int $statusCode
156
     * @return void
157
     */
158
    protected function sendAjaxError($error, array $request, $statusCode = 400)
159
    {
160
        glsr_log()->error($error)->debug($request);
161
        glsr(Notice::class)->addError(__('There was an error (try reloading the page).', 'site-reviews').' <code>'.$error.'</code>');
162
        wp_send_json_error([
163
            'message' => __('The form could not be submitted. Please notify the site administrator.', 'site-reviews'),
164
            'notices' => glsr(Notice::class)->get(),
165
            'error' => $error,
166
        ]);
167
    }
168
}
169