PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.7
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / Background / LPAsyncRequest.php

LPAsyncRequest.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.7, at inc/Background/LPAsyncRequest.php

238 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 LearnPress\Background;
4
5 use WP_Error;
6
7 /**
8 * Abstract LP_Async_Request class.
9 *
10 * This class is used to create asynchronous requests in LearnPress.
11 * It is recommended to use this class for tasks that can be processed in the background
12 * It is non-blocking, therefore it does not return data when done.
13 * Note: don't call too many times on a progress, it can cause server hang.
14 * Should be considered when using
15 *
16 * @since 4.2.8.7 instead of LP_Async_Request since 4.1.6.9.4, only change class name to autoload
17 * @version 1.0.0
18 */
19 abstract class LPAsyncRequest {
20 /**
21 * Prefix
22 * @var string
23 */
24 protected $prefix = 'lp';
25
26 /**
27 * Action
28 * @var string
29 */
30 protected $action = 'async_request';
31
32 /**
33 * Identifier
34 *
35 * @var string
36 */
37 protected $identifier;
38
39 /**
40 * Constant identifier for a task that should be available to logged-in users
41 */
42 const LOGGED_IN = 1;
43
44 /**
45 * Constant identifier for a task that should be available to logged-out users
46 */
47 const LOGGED_OUT = 2;
48
49 /**
50 * Constant identifier for a task that should be available to all users regardless of auth status
51 */
52 const BOTH = 3;
53
54 /**
55 * Data
56 *
57 * (default value: array())
58 *
59 * @var array
60 */
61 protected $data = array();
62
63 /**
64 * Initiate new async request
65 */
66 public function __construct( $auth_level = self::BOTH ) {
67 $this->identifier = $this->prefix . '_' . $this->action;
68
69 //add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
70 //add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
71
72 if ( $auth_level & self::LOGGED_IN ) {
73 add_action( "admin_post_lp_async_$this->identifier", [ $this, 'maybe_handle' ] );
74 }
75 if ( $auth_level & self::LOGGED_OUT ) {
76 add_action( "admin_post_nopriv_lp_async_$this->identifier", [ $this, 'maybe_handle' ] );
77 }
78 }
79
80 /**
81 * Set data used during the request
82 *
83 * @param array $data Data.
84 *
85 * @return $this
86 */
87 public function data( array $data ): LPAsyncRequest {
88 $this->data = $data;
89
90 return $this;
91 }
92
93 /**
94 * Dispatch the async request
95 *
96 * @return array|WP_Error
97 */
98 public function dispatch() {
99 $url = esc_url_raw( $this->get_query_url() );
100 $args = $this->get_post_args();
101
102 return wp_remote_post( $url, $args );
103 }
104
105 /**
106 * Get query URL
107 *
108 * @return string
109 */
110 protected function get_query_url(): string {
111 if ( property_exists( $this, 'query_url' ) ) {
112 return $this->query_url;
113 }
114
115 $url = admin_url( 'admin-post.php' );
116 return apply_filters( $this->identifier . '/query_url', $url );
117 }
118
119 /**
120 * Get post args
121 *
122 * @return array
123 */
124 protected function get_post_args(): array {
125 $identifier = $this->identifier;
126 $this->data['action'] = "lp_async_{$identifier}";
127 $this->data['_nonce'] = $this->create_async_nonce();
128
129 /**
130 * Must set timeout to 0.01 to avoid blocking the request.
131 * Don't change it, because it can make sever hang.
132 */
133 $args = array(
134 'timeout' => 0.01,
135 'blocking' => false,
136 'body' => $this->data,
137 'cookies' => $_COOKIE,
138 'sslverify' => is_ssl(),
139 );
140
141 /**
142 * Filters the post arguments used during an async request.
143 *
144 * @param array $args
145 */
146 return apply_filters( $this->identifier . '_post_args', $args );
147 }
148
149 /**
150 * Create nonce for async request
151 *
152 * @return false|string
153 */
154 protected function create_async_nonce() {
155 $action = $this->get_nonce_action();
156 $i = wp_nonce_tick();
157
158 return substr( wp_hash( $i . $action . get_class( $this ), 'nonce' ), - 12, 10 );
159 }
160
161 /**
162 * Verify that the correct nonce was used within the time limit.
163 *
164 * @param string $nonce
165 *
166 * @return bool
167 */
168 protected function verify_async_nonce( string $nonce ): bool {
169 $action = $this->get_nonce_action();
170 $i = wp_nonce_tick();
171
172 // Nonce generated 0-12 hours ago
173 if ( substr( wp_hash( $i . $action . get_class( $this ), 'nonce' ), - 12, 10 ) == $nonce ) {
174 return 1;
175 }
176
177 // Nonce generated 12-24 hours ago
178 if ( substr( wp_hash( ( $i - 1 ) . $action . get_class( $this ), 'nonce' ), - 12, 10 ) == $nonce ) {
179 return 2;
180 }
181
182 // Invalid nonce
183 return false;
184 }
185
186 /**
187 * Get a nonce action based on the $action property of the class
188 *
189 * @return string The nonce action for the current instance
190 */
191 protected function get_nonce_action(): string {
192 $action = $this->identifier;
193 if ( substr( $action, 0, 7 ) === 'nopriv_' ) {
194 $action = substr( $action, 7 );
195 }
196
197 return "lp_async_$action";
198 }
199
200 /**
201 * Maybe handle
202 *
203 * Check for correct nonce and pass to handler.
204 */
205 public function maybe_handle() {
206 // Don't lock up other requests while processing
207 session_write_close();
208
209 /**
210 * set params $_POST['lp_no_check_referer'] = 1
211 * for case: send request when user not login, but get request when user logged
212 * @editor tungnx
213 * @modify 4.1.4
214 */
215 /*if ( ! isset( $_POST['lp_no_check_referer'] ) ) {
216 check_ajax_referer( $this->identifier, 'nonce' );
217 }*/
218
219 if ( isset( $_POST['_nonce'] ) && $this->verify_async_nonce( $_POST['_nonce'] ) ) {
220 if ( ! is_user_logged_in() ) {
221 $this->identifier = "nopriv_$this->identifier";
222 }
223
224 $this->handle();
225 }
226
227 wp_die();
228 }
229
230 /**
231 * Handle
232 *
233 * Override this method to perform any actions required
234 * during the async request.
235 */
236 abstract protected function handle();
237 }
238