PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.21
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.21
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / vendor / wpfluent / framework / src / WPFluent / Foundation / AsyncRequestTrait.php

AsyncRequestTrait.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.21, at vendor/wpfluent/framework/src/WPFluent/Foundation/AsyncRequestTrait.php

273 lines 5.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\Framework\Foundation;
4
5 trait AsyncRequestTrait
6 {
7 /**
8 * Async actions names
9 * @var array
10 */
11 protected $asyncActions = [];
12
13 /**
14 * Launchable actions
15 * @var array
16 */
17 protected $launchableActions = [];
18
19 /**
20 * Add an async action
21 *
22 * @param string $action
23 * @param mixed $handler Callback
24 * @return null
25 */
26 public function addAsyncAction($action, $handler)
27 {
28 $this->asyncActions[$action] = $handler;
29 }
30
31 /**
32 * Queue an async action so it'll be dispatched
33 * automatically during the WordPress shutdown hook.
34 *
35 * @param string $action
36 * @param mixed $handler Callback
37 * @param array $data The data to be passed to the handler
38 * @return null
39 */
40 public function queueAsyncAction($action, $handler, $data = [])
41 {
42 $this->addAsyncAction($action, $handler);
43 $this->doAsyncAction($action, $data);
44 }
45
46 /**
47 * Dequeue an async action so it won't be dispatched
48 * automatically during the WordPress shutdown hook.
49 *
50 * @param string $action
51 * @return null
52 */
53 public function dequeueAsyncAction($action)
54 {
55 unset($this->launchableActions[$action]);
56 }
57
58 /**
59 * Dispatch async action
60 * @param string $action
61 * @param array $data
62 * @return null
63 */
64 public function doAsyncAction($action, $data = [])
65 {
66 $this->launchableActions[$action] = $data;
67 }
68
69 /**
70 * Register an async action
71 * @return null
72 */
73 protected function registerAsyncActions()
74 {
75 $this->registerAdminPostAction(
76 $this->config->get('app.slug')
77 );
78 }
79
80 /**
81 * Register an async action in WordPress admin_post_[action]
82 * @param string $slug
83 * @return null
84 */
85 protected function registerAdminPostAction($slug)
86 {
87 add_action("admin_post_wpfluent_async_$slug", [$this, 'callback']);
88 add_action("admin_post_nopriv_wpfluent_async_$slug", [$this, 'callback']);
89
90 if (!has_action('shutdown', [$this, 'launchPostRequest'])) {
91 if (!$this->request->get($this->getAsyncActionIdentifier())) {
92 add_action('shutdown', [$this, 'launchPostRequest']);
93 }
94
95 }
96 }
97
98 /**
99 * The main callback for async actions
100 * @return null
101 * @throws \Exception
102 */
103 public function callback()
104 {
105 add_filter('wp_die_handler', function() { die(); });
106
107 try {
108 $this->verifyNonce();
109
110 foreach ($_POST['actions'] as $action => $data) {
111 try {
112 if (isset($this->asyncActions[$action])) {
113 ($this->parseHookHandler(
114 $this->asyncActions[$action]
115 ))($data);
116 }
117 } catch (\Exception $e) {
118 continue;
119 }
120 }
121 } catch (\Exception $e) {
122 return;
123 }
124 }
125
126 /**
127 * Launch the background (async) request.
128 * @return null
129 */
130 public function launchPostRequest()
131 {
132 if (!$this->hasLaunchableActions()) {
133 return;
134 }
135
136 $data = $this->getData();
137
138 foreach ($this->launchableActions as $key => $action) {
139 $this->dispatchRequest(array_merge(
140 $data, ['actions' => [$key => $action]]
141 ));
142 }
143 }
144
145 /**
146 * Get the post data for the action
147 * @return array
148 */
149 protected function getData()
150 {
151 $slug = $this->getAsyncActionIdentifier();
152
153 return [
154 $slug => true,
155 '_nonce' => $this->createNonce(),
156 'action' => $this->getMainAction()
157 ];
158 }
159
160 /**
161 * Dispatch the request.
162 *
163 * @param array $data
164 * @return null
165 */
166 protected function dispatchRequest($data)
167 {
168 $args = [
169 'timeout' => 0.01,
170 'blocking' => false,
171 'sslverify' => apply_filters('https_local_ssl_verify', true),
172 'body' => $data,
173 'headers' => [
174 'cookie' => $this->getCookie(),
175 ],
176 ];
177
178 wp_remote_post(admin_url('admin-post.php'), $args);
179 }
180
181 /**
182 * Get the unique slug for identifying
183 * the async request for this plugin.
184 *
185 * @return string Unique identifier
186 */
187 protected function getAsyncActionIdentifier()
188 {
189 $slug = $this->config->get('app.slug');
190
191 return '_wpfluent_is_async_request_for_plugin_' . $slug;
192 }
193
194 /**
195 * Get the cookie to send with the request
196 * @return string Cookie string
197 */
198 protected function getCookie()
199 {
200 $cookies = [];
201
202 foreach ($_COOKIE as $name => $value) {
203 $cookies[] = "$name=" . urlencode(is_array($value) ? serialize($value) : $value);
204 }
205
206 return implode('; ', $cookies);
207 }
208
209 /**
210 * Check for any launchable actions.
211 * @return boolean
212 */
213 protected function hasLaunchableActions()
214 {
215 return count($this->launchableActions) > 0;
216 }
217
218 /**
219 * Create the nonce for the request.
220 * @return string
221 */
222 protected function createNonce()
223 {
224 $i = wp_nonce_tick();
225
226 $action = $this->getMainAction();
227
228 return wp_hash($i . $action, 'nonce');
229 }
230
231 /**
232 * Verify the nonce
233 * @return mixed
234 */
235 protected function verifyNonce()
236 {
237 if (!isset($_POST['_nonce'])) {
238 throw new \Exception('Invalid Request.');
239 }
240
241 $nonce = $_POST['_nonce'];
242
243 $i = wp_nonce_tick();
244
245 $action = $this->getMainAction();
246
247 // Nonce generated 0-12 hours ago
248 if (wp_hash($i . $action, 'nonce') == $nonce) {
249 return 1;
250 }
251
252 // Nonce generated 12-24 hours ago
253 if (wp_hash(($i - 1) . $action , 'nonce') == $nonce) {
254 return 2;
255 }
256
257 // Invalid nonce
258 return false;
259 }
260
261 /**
262 * Resolve the main action name for the pliugin.
263 * @return string
264 */
265 protected function getMainAction() {
266 $action = $this->config->get('app.slug');
267
268 $action = "wpfluent_async_$action";
269
270 return $action;
271 }
272 }
273