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