PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 5.1.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v5.1.1
6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 5.2.2 5.3 All 153 releases
mainwp / class / class-mainwp-connect.php

class-mainwp-connect.php in MainWP Dashboard: Self-hosted WordPress Management for Agencies 5.1.1, at class/class-mainwp-connect.php

1,899 lines 75.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MainWP Connect
4 *
5 * MainWP Connect functions.
6 *
7 * @package MainWP/Dashboard
8 */
9
10 namespace MainWP\Dashboard;
11
12 /**
13 * Class MainWP_Connect
14 *
15 * @package MainWP\Dashboard
16 */
17 class MainWP_Connect { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
18
19 // phpcs:disable WordPress.DB.RestrictedFunctions, Generic.Metrics.CyclomaticComplexity, WordPress.WP.AlternativeFunctions, WordPress.PHP.NoSilencedErrors -- Using cURL functions.
20
21 /**
22 * Method get_class_name()
23 *
24 * Get Class Name.
25 *
26 * @return object Class name.
27 */
28 public static function get_class_name() {
29 return __CLASS__;
30 }
31
32 /**
33 * Method try visit.
34 *
35 * Try connecting to Child Site via cURL.
36 *
37 * @param string $url Child Site URL.
38 * @param bool $ssl_verifyhost Option to check SSL Certificate. Default = null.
39 * @param string $http_user HTTPAuth Username. Default = null.
40 * @param string $http_pass HTTPAuth Password. Default = null.
41 * @param int $sslVersion Child Site SSL Version.
42 * @param bool $forceUseIPv4 Option to force IP4. Default = null.
43 * @param bool $no_body Option to set CURLOPT_NOBODY option. Default = false.
44 *
45 * @return array $out. 'host IP, Returned HTTP Code, Error Message, http Status error message.
46 *
47 * @uses \MainWP\Dashboard\MainWP_Logger::debug()
48 * @uses \MainWP\Dashboard\MainWP_System::$version
49 * @uses \MainWP\Dashboard\MainWP_Utility::value_to_string()
50 * @uses \MainWP\Dashboard\MainWP_Utility::get_http_codes()
51 */
52 public static function try_visit( $url, $ssl_verifyhost = null, $http_user = null, $http_pass = null, $sslVersion = 0, $forceUseIPv4 = null, $no_body = false ) { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
53
54 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
55 $postdata = array( 'test' => 'yes' );
56
57 $ch = curl_init();
58
59 $proxy = new \WP_HTTP_Proxy();
60 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
61 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
62 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
63 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
64
65 if ( $proxy->use_authentication() ) {
66 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
67 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
68 }
69 }
70
71 curl_setopt( $ch, CURLOPT_URL, $url );
72 if ( $no_body ) {
73 curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' ); // HTTP request is 'HEAD', but sometime return 4xx - error code.
74 }
75 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
76 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
77 curl_setopt( $ch, CURLOPT_POST, true );
78 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
79 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
80 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
81 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
82
83 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
84 $http_pass = stripslashes( $http_pass );
85 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
86 }
87
88 if ( $ssl_verifyhost ) {
89 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
90 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
91 } else {
92 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); // NOSONAR.
93 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // NOSONAR.
94 }
95
96 curl_setopt( $ch, CURLOPT_SSLVERSION, $sslVersion );
97
98 $http_version = apply_filters( 'mainwp_curl_http_version', false, false, $url );
99 if ( false !== $http_version ) {
100 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
101 }
102
103 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, false, $url );
104 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
105 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
106 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
107 }
108
109 $headers = array( 'X-Requested-With' => 'XMLHttpRequest' );
110 $headers['Expect'] = static::get_expect_header( $postdata );
111
112 if ( class_exists( '\WpOrg\Requests\Requests' ) ) {
113 $headers = \WpOrg\Requests\Requests::flatten( $headers );
114 } else {
115 $headers = \Requests::flatten( $headers );
116 }
117
118 curl_setopt( $ch, CURLOPT_HTTPHEADER, array( 'X-Requested-With: XMLHttpRequest' ) );
119 curl_setopt( $ch, CURLOPT_REFERER, get_option( 'siteurl' ) );
120
121 $force_use_ipv4 = false;
122 if ( null !== $forceUseIPv4 ) {
123 if ( 1 === $forceUseIPv4 ) {
124 $force_use_ipv4 = true;
125 } elseif ( 2 === $forceUseIPv4 ) {
126 if ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
127 $force_use_ipv4 = true;
128 }
129 }
130 } elseif ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
131 $force_use_ipv4 = true;
132 }
133
134 if ( $force_use_ipv4 && defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
135 curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
136 }
137
138 $disabled_functions = ini_get( 'disable_functions' );
139 if ( empty( $disabled_functions ) || ( stristr( $disabled_functions, 'curl_multi_exec' ) === false ) ) {
140 $mh = curl_multi_init();
141 @curl_multi_add_handle( $mh, $ch );
142
143 do {
144 curl_multi_exec( $mh, $running );
145 while ( $info = curl_multi_info_read( $mh ) ) {
146 $data = curl_multi_getcontent( $info['handle'] );
147 $err = curl_error( $info['handle'] );
148 $http_status = curl_getinfo( $info['handle'], CURLINFO_HTTP_CODE );
149 $realurl = curl_getinfo( $info['handle'], CURLINFO_EFFECTIVE_URL );
150
151 curl_multi_remove_handle( $mh, $info['handle'] );
152 }
153 usleep( 10000 );
154 } while ( $running > 0 );
155
156 if ( 'resource' === gettype( $mh ) ) {
157 curl_multi_close( $mh );
158 }
159 } else {
160 $data = curl_exec( $ch );
161 $err = curl_error( $ch );
162 $http_status = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
163 $realurl = curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
164 if ( 'resource' === gettype( $ch ) ) {
165 curl_close( $ch );
166 }
167 }
168
169 MainWP_Logger::instance()->debug( ' :: tryVisit :: [url=' . $url . '] [http_status=' . $http_status . '] [error=' . $err . '] [data-start]' . $data . '[data-end]' );
170 MainWP_Logger::instance()->log_execution_time( 'tryVisit :: [url=' . $url . '] [http_status=' . $http_status . ']' );
171
172 $host = wp_parse_url( ( empty( $realurl ) ? $url : $realurl ), PHP_URL_HOST );
173 $ip = false;
174 $target = false;
175
176 $found = false;
177 $dnsRecord = @dns_get_record( $host );
178 MainWP_Logger::instance()->debug( ' :: tryVisit :: [dnsRecord=' . MainWP_Utility::value_to_string( $dnsRecord, 1 ) . ']' );
179
180 if ( false !== $dnsRecord && is_array( $dnsRecord ) ) {
181 if ( ! isset( $dnsRecord['ip'] ) ) {
182 foreach ( $dnsRecord as $dnsRec ) {
183 if ( isset( $dnsRec['ip'] ) ) {
184 $ip = $dnsRec['ip'];
185 break;
186 }
187 }
188 } else {
189 $ip = $dnsRecord['ip'];
190 }
191
192 if ( ! isset( $dnsRecord['host'] ) ) {
193 foreach ( $dnsRecord as $dnsRec ) {
194 if ( $dnsRec['host'] === $host ) {
195 if ( 'CNAME' === $dnsRec['type'] ) {
196 $target = $dnsRec['target'];
197 }
198 $found = true;
199 break;
200 }
201 }
202 } else {
203 $found = ( $dnsRecord['host'] === $host );
204 if ( 'CNAME' === $dnsRecord['type'] ) {
205 $target = $dnsRecord['target'];
206 }
207 }
208 }
209
210 if ( false === $ip ) {
211 $ip = gethostbynamel( $host );
212 }
213 if ( ( false !== $target ) && ( $target !== $host ) ) {
214 $host .= ' (CNAME: ' . $target . ')';
215 }
216
217 $out = array(
218 'host' => $host,
219 'httpCode' => $http_status,
220 'httpCodeString' => MainWP_Utility::get_http_codes( $http_status ),
221 );
222
223 if ( false !== $ip ) {
224 $out['ip'] = $ip;
225 $found = true;
226 }
227
228 $out['error'] = ( '' === $err && false === $found ? 'Invalid host.' : $err );
229
230 return $out;
231 }
232
233 /**
234 * Method check_ignored_http_code()
235 *
236 * Check if http error code is being ignored.
237 *
238 * @param mixed $value http error code.
239 *
240 * @return bolean True|False.
241 */
242 public static function check_ignored_http_code( $value ) {
243 $value = (int) $value;
244 if ( 200 === $value ) {
245 return true;
246 }
247 $ignored_code = get_option( 'mainwp_ignore_HTTP_response_status', '' );
248 $ignored_code = trim( $ignored_code );
249 if ( ! empty( $ignored_code ) ) {
250 $ignored_code = explode( ',', $ignored_code );
251 foreach ( $ignored_code as $code ) {
252 $code = trim( $code );
253 if ( (int) $value === (int) $code ) {
254 return true;
255 }
256 }
257 }
258 return false;
259 }
260
261 /**
262 * Method check_website_status()
263 *
264 * Check if the Website returns and http errors.
265 *
266 * @param array $website Child Site information.
267 *
268 * @return mixed False|try visit result.
269 *
270 * @uses \MainWP\Dashboard\MainWP_Utility::is_domain_valid()
271 */
272 public static function check_website_status( $website ) {
273 $http_user = null;
274 $http_pass = null;
275 $sslVersion = null;
276 $verifyCertificate = null;
277 $forceUseIPv4 = null;
278 if ( is_object( $website ) && isset( $website->url ) ) {
279 $url = $website->url;
280 $verifyCertificate = isset( $website->verify_certificate ) ? (int) $website->verify_certificate : null;
281 $forceUseIPv4 = $website->force_use_ipv4;
282 $http_user = $website->http_user;
283 $http_pass = $website->http_pass;
284 $sslVersion = $website->ssl_version;
285 } else {
286 $url = $website;
287 }
288
289 if ( ! MainWP_Utility::is_domain_valid( $url ) ) {
290 return false;
291 }
292
293 $ssl_verifyhost = false;
294
295 if ( 1 === $verifyCertificate ) {
296 $ssl_verifyhost = true;
297 } elseif ( 2 === $verifyCertificate || null === $verifyCertificate ) {
298 if ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === get_option( 'mainwp_sslVerifyCertificate' ) ) ) {
299 $ssl_verifyhost = true;
300 }
301 }
302
303 $noBody = false;
304 return static::try_visit( $url, $ssl_verifyhost, $http_user, $http_pass, $sslVersion, $forceUseIPv4, $noBody );
305 }
306
307 /**
308 * Method get_post_data_authed()
309 *
310 * Get authorized $_POST data & build query.
311 *
312 * @param mixed $website Array of Child Site Info.
313 * @param mixed $what What we are posting.
314 * @param null $params Post parameters.
315 *
316 * @return mixed null|http_build_query()
317 */
318 public static function get_post_data_authed( &$website, $what, $params = null ) { //phpcs:ignore -- NOSONAR - complex method.
319 if ( $website && '' !== $what ) {
320 $data = array();
321 $data['user'] = $website->adminname;
322 $data['function'] = $what;
323 $data['nonce'] = wp_rand( 0, 9999 );
324
325 $params_filter = apply_filters( 'mainwp_pre_fetch_authed_data', false, $params, $what, $website );
326 if ( is_array( $params_filter ) && ! empty( $params_filter ) ) {
327 $data = array_merge( $data, $params_filter );
328 }
329
330 if ( null !== $params ) {
331 $data = array_merge( $data, $params );
332 }
333
334 $alg = false;
335 $sign_success = null;
336 $use_seclib = false;
337
338 $data = apply_filters( 'mainwp_get_post_data_authed', $data, $website, $what, $params );
339 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
340 $sign_success = MainWP_Connect_Lib::connect_sign( $what . $data['nonce'], $signature, base64_decode( $website->privkey ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
341 $use_seclib = true;
342 } elseif ( function_exists( 'openssl_verify' ) ) {
343 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
344 $sign_success = static::connect_sign( $what . $data['nonce'], $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
345 if ( false !== $alg ) {
346 $data['sign_algo'] = $alg;
347 }
348 }
349
350 if ( $use_seclib ) {
351 $data['verifylib'] = 1;
352 }
353
354 if ( null !== $sign_success && empty( $sign_success ) ) {
355 $sign_error = '';
356 while ( $msg = openssl_error_string() ) {
357 if ( is_string( $msg ) ) {
358 $sign_error .= $msg;
359 }
360 }
361 MainWP_Logger::instance()->warning_for_website( $website, 'CONNECT SIGN', 'FAILED :: [what=' . ( is_string( $what ) ? $what : '' ) . '] :: [seclib=' . intval( $use_seclib ) . '] :: [algorithm=' . $alg . '] :: [openssl_sign error =' . $sign_error . ']', false );
362 }
363
364 $data['mainwpsignature'] = ! empty( $signature ) ? base64_encode( $signature ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
365
366 /** This filter is documented in ../widgets/widget-mainwp-recent-posts.php */
367 $recent_number = apply_filters( 'mainwp_recent_posts_pages_number', 5 );
368 if ( 5 !== $recent_number ) {
369 $data['recent_number'] = $recent_number;
370 }
371
372 $scan_dir = apply_filters( 'mainwp_stats_scan_dir', false, $website );
373 if ( ! empty( $scan_dir ) ) {
374 $data['scan_dir'] = 1;
375 }
376
377 /**
378 * Current user global.
379 *
380 * @global string
381 */
382 global $current_user;
383
384 if ( ( ! defined( 'DOING_CRON' ) || false === DOING_CRON ) && ( ! defined( 'WP_CLI' ) || false === WP_CLI ) && is_object( $current_user ) && property_exists( $current_user, 'ID' ) && $current_user->ID ) {
385 /**
386 * Filter: mainwp_alter_login_user
387 *
388 * Filters users accounts so it allows you user to jump to child site under alternative administrator account.
389 *
390 * @param int $website->id Child site ID.
391 * @param int $current_user->ID User ID.
392 *
393 * @since Unknown
394 */
395 $alter_user = apply_filters( 'mainwp_alter_login_user', false, $website->id, $current_user->ID );
396 if ( ! empty( $alter_user ) ) {
397 $data['alt_user'] = rawurlencode( $alter_user );
398 }
399 }
400
401 return http_build_query( $data, '', '&' );
402 }
403
404 return null;
405 }
406
407 /**
408 * Method get_renew_post_data_authed()
409 *
410 * Get authorized $_POST data & build query for renew connection action only.
411 *
412 * @param mixed $website Array of Child Site Info.
413 * @param mixed $what What we are posting.
414 *
415 * @return mixed null|http_build_query()
416 */
417 private static function get_renew_post_data_authed( &$website, $what ) { // phpcs:ignore -- NOSONAR - complex.
418
419 if ( $website && '' !== $what ) {
420 $compat_what = 'disconnect'; // to compatible, renew will call disconnect.
421 $data = array();
422 $data['user'] = $website->adminname;
423 $data['function'] = $compat_what;
424 $data['nonce'] = wp_rand( 0, 9999 );
425
426 $alg = false;
427 $sign_success = null;
428 $use_seclib = false;
429
430 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
431 // to disconnect.
432 $sign_success = MainWP_Connect_Lib::connect_sign( $compat_what . $data['nonce'], $signature, base64_decode( $website->privkey ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
433 $use_seclib = true;
434 } elseif ( function_exists( 'openssl_verify' ) ) {
435 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
436 $sign_success = static::connect_sign( $compat_what . $data['nonce'], $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for keys encoding.
437 if ( empty( $sign_success ) ) { // error from openssl, openssl_sign().
438 $alg = defined( 'OPENSSL_ALGO_SHA1' ) ? OPENSSL_ALGO_SHA1 : false; // to set default SHA1, to disconnect.
439 MainWP_Logger::instance()->debug_for_website( $website, 'get_renew_post_data_authed', '[' . $website->url . '] :: [openssl_sign:failed] :: Set sign_algo=SHA1' );
440 $sign_success = static::connect_sign( $compat_what . $data['nonce'], $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for keys encoding.
441 }
442
443 if ( false !== $alg ) {
444 $data['sign_algo'] = $alg;
445 }
446 }
447
448 if ( $use_seclib ) {
449 $data['verifylib'] = 1;
450 }
451
452 if ( null !== $sign_success && empty( $sign_success ) ) {
453 $sign_error = '';
454 while ( $msg = openssl_error_string() ) {
455 if ( is_string( $msg ) ) {
456 $sign_error .= $msg;
457 }
458 }
459 MainWP_Logger::instance()->warning_for_website( $website, 'CONNECT SIGN', 'FAILED :: [what=' . ( is_string( $what ) ? $what : '' ) . '] :: [seclib=' . intval( $use_seclib ) . '] :: [algorithm=' . $alg . '] :: [openssl_sign error =' . $sign_error . ']', false );
460 }
461
462 $data['mainwpsignature'] = ! empty( $signature ) ? base64_encode( $signature ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
463
464 return http_build_query( $data, '', '&' );
465 }
466 return null;
467 }
468
469
470 /**
471 * Method get_get_data_authed()
472 *
473 * Get authorized $_GET data & build query.
474 *
475 * @param mixed $website Child Site data.
476 * @param mixed $paramValue OpenSSL parameter.
477 * @param string $paramName Parameter name.
478 * @param bool $asArray true|false Default is false.
479 * @param array $other_params other params.
480 *
481 * @return string $url
482 */
483 public static function get_get_data_authed( $website, $paramValue, $paramName = 'where', $asArray = false, $other_params = array() ) { //phpcs:ignore -- NOSONAR - complex method.
484 $params = array();
485 if ( $website && '' !== $paramValue ) {
486
487 $sign_success = null;
488 $alg = false;
489 $use_seclib = false;
490 $nonce = wp_rand( 0, 9999 );
491 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
492 $sign_success = MainWP_Connect_Lib::connect_sign( $paramValue . $nonce, $signature, base64_decode( $website->privkey ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
493 $use_seclib = true;
494 } elseif ( function_exists( 'openssl_verify' ) ) {
495 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
496 $sign_success = static::connect_sign( $paramValue . $nonce, $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
497 }
498
499 $signature = ! empty( $signature ) ? base64_encode( $signature ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
500
501 if ( null !== $sign_success && empty( $sign_success ) ) {
502 $sign_error = '';
503 while ( $msg = openssl_error_string() ) {
504 if ( is_string( $msg ) ) {
505 $sign_error .= $msg;
506 }
507 }
508 MainWP_Logger::instance()->warning_for_website( $website, 'CONNECT SIGN', 'FAILED :: [login_required=1] :: [seclib=' . intval( $use_seclib ) . '] :: [algorithm=' . $alg . '] :: [openssl_sign error =' . $sign_error . ']', false );
509 }
510
511 $params = array(
512 'login_required' => 1,
513 'user' => rawurlencode( $website->adminname ),
514 'mainwpsignature' => rawurlencode( $signature ),
515 'nonce' => $nonce,
516 $paramName => rawurlencode( $paramValue ),
517 );
518
519 if ( is_array( $other_params ) ) {
520 foreach ( $other_params as $name => $value ) {
521 if ( is_string( $name ) && ! empty( $name ) && is_scalar( $value ) ) {
522 $params[ sanitize_text_field( wp_unslash( $name ) ) ] = rawurlencode( sanitize_text_field( wp_unslash( $value ) ) );
523 }
524 }
525 }
526
527 if ( ! empty( $params['login_required'] ) && ! empty( $params['where'] ) ) {
528 $open_params = apply_filters( 'mainwp_open_site_login_required_params', false, $params, $website );
529 if ( is_array( $open_params ) && ! empty( $open_params ) ) {
530 $where_params = '';
531 foreach ( $open_params as $key => $value ) {
532 $where_params .= rawurlencode( sanitize_text_field( wp_unslash( $key ) ) ) . '=' . rawurlencode( sanitize_text_field( wp_unslash( $value ) ) ) . '&';
533 }
534 if ( ! empty( $where_params ) ) {
535 $params['where_params'] = rawurlencode( rtrim( $where_params, '&' ) );
536 }
537 }
538 }
539
540 if ( false !== $alg ) {
541 $params['sign_algo'] = $alg;
542 }
543
544 if ( ! empty( $use_seclib ) ) {
545 $params['verifylib'] = 1;
546 }
547
548 /**
549 * Current user global.
550 *
551 * @global string
552 */
553 global $current_user;
554
555 if ( ( ( ! defined( 'DOING_CRON' ) || false === DOING_CRON ) && ( ! defined( 'WP_CLI' ) || false === WP_CLI ) ) && $current_user && $current_user->ID ) {
556 /** This filter is documented in ../class/class-mainwp-connect.php */
557 $alter_user = apply_filters( 'mainwp_alter_login_user', false, $website->id, $current_user->ID );
558 if ( ! empty( $alter_user ) ) {
559 $params['alt_user'] = rawurlencode( $alter_user );
560 }
561 }
562 }
563
564 if ( $asArray ) {
565 return $params;
566 }
567
568 $url = ( isset( $website->url ) && '' !== $website->url ? $website->url : $website->siteurl );
569 $url .= ( substr( $url, - 1 ) !== '/' ? '/' : '' );
570 $url .= '?';
571
572 foreach ( $params as $key => $value ) {
573 $url .= $key . '=' . $value . '&';
574 }
575 return rtrim( $url, '&' );
576 }
577
578 /**
579 * Method connect_sign()
580 *
581 * Sign connect.
582 *
583 * @param string $data Data sign.
584 * @param string $signature signature.
585 * @param string $privkey Private key.
586 * @param mixed $algorithm signature algorithm.
587 *
588 * @return bool Success or not.
589 */
590 public static function connect_sign( $data, &$signature, $privkey, $algorithm ) {
591 if ( false === $algorithm ) {
592 return openssl_sign( $data, $signature, $privkey ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
593 } else {
594 return openssl_sign( $data, $signature, $privkey, $algorithm ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
595 }
596 }
597
598 /**
599 * Method get_post_data_not_authed()
600 *
601 * Get not authorized $_POST data.
602 *
603 * @param mixed $url Child site URL.
604 * @param mixed $admin Admin Username.
605 * @param mixed $what What function to perform.
606 * @param null $params Function parameters.
607 *
608 * @return mixed null|http_build_query()
609 */
610 public static function get_post_data_not_authed( $url, $admin, $what, $params = null ) {
611 if ( '' !== $url && '' !== $admin && '' !== $what ) {
612 $data = array();
613 $data['user'] = $admin;
614 $data['function'] = $what;
615 if ( null !== $params ) {
616 $data = array_merge( $data, $params );
617 }
618
619 return http_build_query( $data, '', '&' );
620 }
621
622 return null;
623 }
624
625 /**
626 * Method fetch_urls_authed()
627 *
628 * Fetch authorized URLs.
629 *
630 * @param object $websites Websites information.
631 * @param string $what Action to perform.
632 * @param array $params Request parameters.
633 * @param mixed $handler Request handler.
634 * @param mixed $output Request output.
635 * @param mixed $whatPage Request URL. Default /admin-ajax.php.
636 * @param array $others Request additional information.
637 *
638 * @return bool true|false
639 *
640 * @uses \MainWP\Dashboard\MainWP_System::$version
641 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
642 */
643 public static function fetch_urls_authed( &$websites, $what, $params, $handler, &$output, $whatPage = null, $others = array() ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity -- NOSONAR - complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
644
645 if ( ! is_array( $websites ) || empty( $websites ) ) {
646 return false;
647 }
648
649 if ( ! is_array( $params ) ) {
650 $params = array();
651 }
652
653 $chunkSize = apply_filters( 'mainwp_fetch_urls_chunk_size', 10 );
654 if ( count( $websites ) > $chunkSize ) {
655 $total = count( $websites );
656 $loops = ceil( $total / $chunkSize );
657 for ( $i = 0; $i < $loops; $i++ ) {
658 $newSites = array_slice( $websites, $i * $chunkSize, $chunkSize, true );
659 static::fetch_urls_authed( $newSites, $what, $params, $handler, $output, $whatPage, $others );
660 sleep( 5 );
661 }
662
663 return false;
664 }
665
666 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
667 $mh = curl_multi_init();
668
669 $timeout = 20 * 60 * 60;
670
671 $disabled_functions = ini_get( 'disable_functions' );
672 $handleToWebsite = array();
673 $requestUrls = array();
674 $requestHandles = array();
675
676 $dirs = MainWP_System_Utility::get_mainwp_dir();
677 $cookieDir = $dirs[0] . 'cookies';
678
679 static::init_cookiesdir( $cookieDir );
680
681 $_org_params = null;
682
683 foreach ( $websites as $website ) {
684
685 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
686 MainWP_Demo_Handle::get_instance()->handle_fetch_urls_demo( $data, $website, $output, $what, $params );
687 continue;
688 }
689
690 $url = $website->url;
691 if ( '/' !== substr( $url, - 1 ) ) {
692 $url .= '/';
693 }
694
695 if ( false === strpos( $url, 'wp-admin' ) ) {
696 $url .= 'wp-admin/';
697 }
698
699 if ( null !== $whatPage ) {
700 $url .= $whatPage;
701 } else {
702 $url .= 'admin-ajax.php';
703 }
704
705 if ( property_exists( $website, 'http_user' ) ) {
706 $http_user = $website->http_user;
707 }
708 if ( property_exists( $website, 'http_pass' ) ) {
709 $http_pass = $website->http_pass;
710 }
711
712 if ( isset( $params ) && isset( $params['new_post'] ) ) {
713
714 if ( null === $_org_params ) {
715 $_org_params = $params;
716 }
717
718 /**
719 * Filter is being replaced with mainwp_pre_posting_posts.
720 *
721 * @deprecated
722 */
723 $params = apply_filters_deprecated(
724 'mainwp-pre-posting-posts',
725 array(
726 ( is_array( $params ) ? $params : array() ),
727 (object) array(
728 'id' => $website->id,
729 'url' => $website->url,
730 'name' => $website->name,
731 ),
732 ),
733 '4.0.7.2', // NOSONAR - not IP.
734 'mainwp_pre_posting_posts'
735 );
736
737 /**
738 * Filter: mainwp_pre_posting_posts
739 *
740 * Prepares parameters for the authenticated cURL post.
741 *
742 * @since 4.1
743 */
744 $params = apply_filters(
745 'mainwp_pre_posting_posts',
746 ( is_array( $params ) ? $params : array() ),
747 (object) array(
748 'id' => $website->id,
749 'url' => $website->url,
750 'name' => $website->name,
751 )
752 );
753 }
754
755 $ch = curl_init();
756
757 $proxy = new \WP_HTTP_Proxy();
758 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
759 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
760 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
761 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
762
763 if ( $proxy->use_authentication() ) {
764 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
765 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
766 }
767 }
768
769 if ( ( null !== $website ) && ( ( property_exists( $website, 'wpe' ) && 1 !== $website->wpe ) || ( isset( $others['upgrade'] ) && ( true === $others['upgrade'] ) ) ) ) {
770 // to fix.
771 if ( defined( 'LOGGED_IN_SALT' ) && defined( 'NONCE_SALT' ) ) {
772 $cookie_salt = sha1( sha1( 'mainwp' . LOGGED_IN_SALT . $website->id ) . NONCE_SALT . 'WP_Cookie' ); // NOSONAR - safe for salt file name.
773 } else {
774 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' ); // NOSONAR - safe for salt file name.
775 }
776 $cookieFile = $cookieDir . '/' . $cookie_salt;
777 if ( ! file_exists( $cookieFile ) ) {
778 @file_put_contents( $cookieFile, '' );
779 }
780
781 if ( file_exists( $cookieFile ) ) {
782 @chmod( $cookieFile, 0644 ); // NOSONAR - correct file permissions, owner: rwe, group & others: r.
783 curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookieFile );
784 curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookieFile );
785 }
786 }
787
788 curl_setopt( $ch, CURLOPT_URL, $url );
789 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
790 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
791 curl_setopt( $ch, CURLOPT_POST, true );
792
793 $postdata = static::get_post_data_authed( $website, $what, $params );
794 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
795 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
796 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
797 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
798 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
799 $http_pass = stripslashes( $http_pass );
800 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
801 }
802
803 $ssl_verifyhost = false;
804 $verifyCertificate = isset( $website->verify_certificate ) ? (int) $website->verify_certificate : null;
805 if ( null !== $verifyCertificate ) {
806 if ( 1 === $verifyCertificate ) {
807 $ssl_verifyhost = true;
808 } elseif ( 2 === $verifyCertificate ) {
809 if ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) {
810 $ssl_verifyhost = true;
811 }
812 }
813 } elseif ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) {
814 $ssl_verifyhost = true;
815 }
816
817 if ( $ssl_verifyhost ) {
818 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
819 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
820 } else {
821 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); // NOSONAR.
822 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // NOSONAR.
823 }
824
825 curl_setopt( $ch, CURLOPT_SSLVERSION, $website->ssl_version );
826
827 if ( is_object( $website ) && property_exists( $website, 'id' ) ) {
828 $http_version = apply_filters( 'mainwp_curl_http_version', false, $website->id );
829 if ( false !== $http_version ) {
830 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
831 }
832
833 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, $website->id, $website->url );
834 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
835 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
836 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
837 }
838 }
839
840 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
841 MainWP_System_Utility::set_time_limit( $timeout );
842
843 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
844 @curl_multi_add_handle( $mh, $ch );
845 }
846
847 $handleToWebsite[ static::get_resource_id( $ch ) ] = $website;
848 $requestUrls[ static::get_resource_id( $ch ) ] = $website->url;
849 $requestHandles[ static::get_resource_id( $ch ) ] = $ch;
850
851 if ( null !== $_org_params ) {
852 $params = $_org_params;
853 }
854 }
855
856 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
857 $lastRun = 0;
858 do {
859 if ( 20 < time() - $lastRun ) {
860 MainWP_System_Utility::set_time_limit( $timeout );
861 $lastRun = time();
862 }
863
864 curl_multi_exec( $mh, $running );
865 while ( $info = curl_multi_info_read( $mh ) ) {
866 $data = curl_multi_getcontent( $info['handle'] );
867 $contains = ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) );
868 curl_multi_remove_handle( $mh, $info['handle'] );
869
870 if ( ! $contains && isset( $requestUrls[ static::get_resource_id( $info['handle'] ) ] ) ) {
871 curl_setopt( $info['handle'], CURLOPT_URL, $requestUrls[ static::get_resource_id( $info['handle'] ) ] );
872 curl_multi_add_handle( $mh, $info['handle'] );
873 unset( $requestUrls[ static::get_resource_id( $info['handle'] ) ] );
874 ++$running;
875 continue;
876 }
877
878 if ( null !== $handler ) {
879 $site = &$handleToWebsite[ static::get_resource_id( $info['handle'] ) ];
880 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
881 }
882
883 unset( $handleToWebsite[ static::get_resource_id( $info['handle'] ) ] );
884 if ( 'resource' === gettype( $info['handle'] ) ) {
885 curl_close( $info['handle'] );
886 }
887 unset( $info['handle'] );
888 }
889 usleep( 10000 );
890 } while ( $running > 0 );
891
892 if ( 'resource' === gettype( $mh ) ) {
893 curl_multi_close( $mh );
894 }
895 } else {
896 foreach ( $requestHandles as $ch ) {
897 $data = curl_exec( $ch );
898
899 if ( null !== $handler ) {
900 $site = &$handleToWebsite[ static::get_resource_id( $ch ) ];
901 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
902 }
903 }
904 }
905
906 return true;
907 }
908
909 /**
910 * Credits WordPress org.
911 *
912 * Get the correct "Expect" header for the given request data.
913 *
914 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
915 * @return string The "Expect" header.
916 */
917 protected static function get_expect_header( $data ) {
918 if ( ! is_array( $data ) ) {
919 return strlen( (string) $data ) >= 1048576 ? '100-Continue' : '';
920 }
921
922 $bytesize = 0;
923 $iterator = new \RecursiveIteratorIterator( new \RecursiveArrayIterator( $data ) );
924
925 foreach ( $iterator as $datum ) {
926 $bytesize += strlen( (string) $datum );
927
928 if ( $bytesize >= 1048576 ) {
929 return '100-Continue';
930 }
931 }
932
933 return '';
934 }
935
936 /**
937 * Method get_resource_id()
938 *
939 * Get resource id.
940 *
941 * @param mixed $res The given resource.
942 *
943 * @return $result Resource ID only.
944 */
945 public static function get_resource_id( $res ) {
946 $result = false;
947 if ( is_a( $res, 'CurlHandle' ) ) {
948 $result = spl_object_hash( $res );
949 } elseif ( is_resource( $res ) ) {
950 $resourceString = (string) $res;
951 $exploded = explode( '#', $resourceString );
952 $result = array_pop( $exploded );
953 }
954 return $result;
955 }
956
957 /**
958 * Method get_lock_identifier().
959 *
960 * Get lock identifier.
961 *
962 * @param mixed $pLockName Provided Lock Name.
963 *
964 * @return mixed false|sem_get()|@fopen
965 */
966 public static function get_lock_identifier( $pLockName ) {
967 if ( ( null === $pLockName ) || ( false === $pLockName ) ) {
968 return false;
969 }
970
971 if ( function_exists( 'sem_get' ) ) {
972 return sem_get( $pLockName );
973 } else {
974 $fh = @fopen( sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'lock' . $pLockName . '.txt', 'w+' );
975 if ( ! $fh ) {
976 return false;
977 }
978
979 return $fh;
980 }
981 }
982
983 /**
984 * Method lock()
985 *
986 * Use sem_acquire or @flock to lock the $identifier.
987 *
988 * @param mixed $identifier Identifier.
989 *
990 * @return mixed false|sem_acquire()|@flock
991 */
992 public static function lock( $identifier ) {
993 if ( ( null === $identifier ) || ( false === $identifier ) ) {
994 return false;
995 }
996
997 if ( function_exists( 'sem_acquire' ) ) {
998 return sem_acquire( $identifier );
999 } else {
1000 if ( ! is_resource( $identifier ) ) {
1001 return false; // to fix.
1002 }
1003 for ( $i = 0; $i < 3; $i++ ) {
1004 if ( @flock( $identifier, LOCK_EX ) ) {
1005 return $identifier;
1006 } else {
1007 sleep( 1 );
1008 }
1009 }
1010 return false;
1011 }
1012 }
1013
1014 /**
1015 * Method release()
1016 *
1017 * Use sem_release or @flock, @fclose to unlock $identifier.
1018 *
1019 * @param mixed $identifier Identifier.
1020 *
1021 * @return mixed false|sem_release()|@flock
1022 */
1023 public static function release( $identifier ) {
1024 if ( ( null === $identifier ) || ( false === $identifier ) ) {
1025 return false;
1026 }
1027
1028 if ( function_exists( 'sem_release' ) ) {
1029 return sem_release( $identifier );
1030 } else {
1031 if ( ! is_resource( $identifier ) ) {
1032 return false; // to fix.
1033 }
1034 @flock( $identifier, LOCK_UN );
1035 @fclose( $identifier );
1036 }
1037
1038 return false;
1039 }
1040
1041 /**
1042 * Method fetch_url_authed()
1043 *
1044 * Updates the child site via authenticated request.
1045 *
1046 * @param object $website Website information.
1047 * @param string $what Function to perform.
1048 * @param null $params Function parameters.
1049 * @param bool $checkConstraints Whether or not to check constraints.
1050 * @param bool $pForceFetch Whether or not to force the fetch.
1051 * @param bool $pRetryFailed Whether or not to retry the fetch process.
1052 * @param null $rawResponse Raw response.
1053 *
1054 * @return mixed $information
1055 *
1056 * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::handle_check_website()
1057 * @uses \MainWP\Dashboard\MainWP_Premium_Update::maybe_request_premium_updates()
1058 * @uses \MainWP\Dashboard\MainWP_Sync::sync_information_array()
1059 */
1060 public static function fetch_url_authed( // phpcs:ignore -- NOSONAR - complex.
1061 &$website,
1062 $what,
1063 $params = null,
1064 $checkConstraints = false,
1065 $pForceFetch = false,
1066 $pRetryFailed = true,
1067 $rawResponse = null
1068 ) {
1069 unset( $pForceFetch );
1070
1071 // to support demo data.
1072 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
1073 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $website, $what );
1074 }
1075
1076 if ( ! is_array( $params ) ) {
1077 $params = array();
1078 }
1079
1080 $others = array(
1081 'force_use_ipv4' => $website->force_use_ipv4,
1082 'upgrade' => ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ),
1083 );
1084
1085 $request_update = MainWP_Premium_Update::maybe_request_premium_updates( $website, $what, $params );
1086
1087 if ( isset( $rawResponse ) && $rawResponse ) {
1088 $others['raw_response'] = 'yes';
1089 }
1090
1091 $params['optimize'] = ( ( 1 === (int) get_option( 'mainwp_optimize', 1 ) ) ? 1 : 0 );
1092
1093 $updating_website = false;
1094 $type = '';
1095 $list = '';
1096 if ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ) {
1097 $updating_website = true;
1098 if ( 'upgradeplugintheme' === $what || 'upgradetranslation' === $what ) {
1099 $type = $params['type'];
1100 $list = $params['list'];
1101 } else {
1102 $type = 'wp';
1103 $list = '';
1104 }
1105 }
1106
1107 if ( $updating_website ) {
1108 /**
1109 * Action: mainwp_website_before_updated
1110 *
1111 * Fires before the child site update process.
1112 *
1113 * @param object $website Object containing child site info.
1114 * @param string $type Type parameter.
1115 * @param string $list List parameter.
1116 *
1117 * @since Unknown
1118 */
1119 do_action( 'mainwp_website_before_updated', $website, $type, $list );
1120 }
1121
1122 if ( 'renew' === $what ) {
1123 $postdata = static::get_renew_post_data_authed( $website, $what );
1124 } else {
1125 $postdata = static::get_post_data_authed( $website, $what, $params );
1126
1127 }
1128 $others['function'] = $what;
1129
1130 $information = array();
1131
1132 if ( ! $request_update ) {
1133 $information = static::fetch_url( $website, $website->url, $postdata, $checkConstraints, $website->verify_certificate, $pRetryFailed, $website->http_user, $website->http_pass, $website->ssl_version, $others );
1134 /**
1135 * Fires immediately after fetch url action.
1136 *
1137 * @param object $website website.
1138 * @param array $information information result data.
1139 * @param string $what action.
1140 * @param array $params params input array.
1141 * @param array $others others input array.
1142 *
1143 * @since 4.5.1.1
1144 */
1145 do_action( 'mainwp_fetch_url_authed', $website, $information, $what, $params, $others );
1146 } else {
1147 $slug = $params['list'];
1148 $information['upgrades'] = array( $slug => 1 );
1149 }
1150
1151 if ( is_array( $information ) && isset( $information['sync'] ) && ! empty( $information['sync'] ) ) {
1152 MainWP_Sync::sync_information_array( $website, $information['sync'] );
1153 unset( $information['sync'] );
1154 }
1155
1156 if ( $updating_website ) {
1157 /**
1158 * Action: mainwp_website_updated
1159 *
1160 * Fires after the child site update process.
1161 *
1162 * @param object $website Object containing child site info.
1163 * @param string $type Type parameter.
1164 * @param string $list List parameter.
1165 * @param array $information Array containing the information fetched from the child site.
1166 *
1167 * @since Unknown
1168 */
1169 do_action( 'mainwp_website_updated', $website, $type, $list, $information );
1170 if ( 1 === (int) get_option( 'mainwp_check_http_response', 0 ) ) {
1171 MainWP_Monitoring_Handler::handle_check_website( $website );
1172 }
1173 }
1174
1175 return $information;
1176 }
1177
1178 /**
1179 * Method fetch_url_not_authed()
1180 *
1181 * Fetch not authorized URL.
1182 *
1183 * @param string $url URL to fetch from.
1184 * @param string $admin Admin name.
1185 * @param string $what Function to perform.
1186 * @param null $params Function parameters.
1187 * @param bool $pForceFetch true|false Whether or not to force the fetch.
1188 * @param null $verifyCertificate Verify the SSL Certificate.
1189 * @param null $http_user htaccess username.
1190 * @param null $http_pass htaccess password.
1191 * @param integer $sslVersion SSL version to check for.
1192 * @param array $others Other functions to perform.
1193 * @param array $output Output values.
1194 *
1195 * @return mixed static::fetch_url() Fetch URL.
1196 */
1197 public static function fetch_url_not_authed( // NOSONAR - compatible.
1198 $url,
1199 $admin,
1200 $what,
1201 $params = null,
1202 $pForceFetch = false,
1203 $verifyCertificate = null,
1204 $http_user = null,
1205 $http_pass = null,
1206 $sslVersion = 0,
1207 $others = array(),
1208 &$output = array()
1209 ) {
1210 unset( $pForceFetch );
1211
1212 if ( empty( $params ) ) {
1213 $params = array();
1214 }
1215
1216 $postdata = static::get_post_data_not_authed( $url, $admin, $what, $params );
1217 $website = null;
1218
1219 $others['function'] = $what;
1220 return static::fetch_url( $website, $url, $postdata, false, $verifyCertificate, true, $http_user, $http_pass, $sslVersion, $others, $output );
1221 }
1222
1223 /**
1224 * Method fetch_url()
1225 *
1226 * Fetch URL.
1227 *
1228 * @param object $website Child Site info.
1229 * @param string $url URL to fetch from.
1230 * @param mixed $postdata Post data to fetch.
1231 * @param bool $checkConstraints true|false Whether or not to check constraints.
1232 * @param null $verifyCertificate Verify SSL Certificate.
1233 * @param bool $pRetryFailed ture|false Whether or not the Retry has failed.
1234 * @param null $http_user htaccess username.
1235 * @param null $http_pass htaccess password.
1236 * @param integer $sslVersion SSL version.
1237 * @param array $others Other functions to perform.
1238 * @param array $output Output values.
1239 *
1240 * @throws \Exception Exception message.
1241 *
1242 * @return mixed static::fetch_url_site()
1243 */
1244 public static function fetch_url( // phpcs:ignore -- NOSONAR - complex.
1245 &$website,
1246 $url,
1247 $postdata,
1248 $checkConstraints = false,
1249 $verifyCertificate = null,
1250 $pRetryFailed = true,
1251 $http_user = null,
1252 $http_pass = null,
1253 $sslVersion = 0,
1254 $others = array(),
1255 &$output = array()
1256 ) {
1257
1258 $start = time();
1259
1260 try {
1261 $tmpUrl = $url;
1262 if ( '/' !== substr( $tmpUrl, - 1 ) ) {
1263 $tmpUrl .= '/';
1264 }
1265
1266 if ( false === strpos( $url, 'wp-admin' ) ) {
1267 $tmpUrl .= 'wp-admin/admin-ajax.php';
1268 }
1269
1270 return static::fetch_url_site( $website, $tmpUrl, $postdata, $checkConstraints, $verifyCertificate, $http_user, $http_pass, $sslVersion, $others, $output );
1271 } catch ( \Exception $e ) {
1272 if ( ! $pRetryFailed || ( 30 < ( time() - $start ) ) ) {
1273 throw $e;
1274 }
1275
1276 try {
1277 return static::fetch_url_site( $website, $url, $postdata, $checkConstraints, $verifyCertificate, $http_user, $http_pass, $sslVersion, $others, $output );
1278 } catch ( \Exception $ex ) {
1279 throw $e;
1280 }
1281 }
1282 }
1283
1284 /**
1285 * Method fetch_url_site()
1286 *
1287 * M Fetch URL.
1288 *
1289 * @param object $website Child Site info.
1290 * @param string $url URL to fetch from.
1291 * @param mixed $postdata Post data to fetch.
1292 * @param bool $checkConstraints true|false Whether or not to check constraints.
1293 * @param null $verifyCertificate Verify SSL Certificate.
1294 * @param null $http_user htaccess username.
1295 * @param null $http_pass htaccess password.
1296 * @param integer $sslVersion SSL version.
1297 * @param array $others Other functions to perform.
1298 * @param array $output Output values.
1299 *
1300 * @return mixed $data, $information.
1301 * @throws MainWP_Exception Exception message.
1302 *
1303 * @uses \MainWP\Dashboard\MainWP_DB_Common::insert_or_update_request_log()
1304 * @uses \MainWP\Dashboard\MainWP_Exception
1305 * @uses \MainWP\Dashboard\MainWP_Logger::debug_for_website()
1306 * @uses \MainWP\Dashboard\MainWP_System::$version
1307 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
1308 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_child_response()
1309 * @uses \MainWP\Dashboard\MainWP_Utility::value_to_string()
1310 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
1311 */
1312 public static function fetch_url_site( // phpcs:ignore -- NOSONAR - complex method. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
1313 &$website,
1314 $url,
1315 $postdata,
1316 $checkConstraints = false,
1317 $verifyCertificate = null,
1318 $http_user = null,
1319 $http_pass = null,
1320 $sslVersion = 0,
1321 $others = array(),
1322 &$output = array()
1323 ) {
1324
1325 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1326
1327 if ( ! empty( $website ) ) {
1328 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Request to [' . $url . '] [' . MainWP_Utility::value_to_string( $postdata, 1 ) . ']' );
1329 }
1330
1331 $identifier = null;
1332 if ( $checkConstraints ) {
1333 static::check_constraints( $identifier, $website );
1334 }
1335
1336 if ( null !== $website ) {
1337 MainWP_DB_Common::instance()->insert_or_update_request_log( $website->id, null, microtime( true ), null );
1338 }
1339
1340 if ( null !== $identifier ) {
1341 static::release( $identifier );
1342 }
1343
1344 $dirs = MainWP_System_Utility::get_mainwp_dir();
1345 $cookieDir = $dirs[0] . 'cookies';
1346
1347 static::init_cookiesdir( $cookieDir );
1348
1349 $ch = curl_init();
1350
1351 $proxy = new \WP_HTTP_Proxy();
1352 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1353 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1354 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1355 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1356
1357 if ( $proxy->use_authentication() ) {
1358 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1359 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1360 }
1361 }
1362
1363 if ( ( null !== $website ) && ( ( property_exists( $website, 'wpe' ) && 1 !== $website->wpe ) || ( isset( $others['upgrade'] ) && ( true === $others['upgrade'] ) ) ) ) {
1364 // to fix.
1365 if ( defined( 'LOGGED_IN_SALT' ) && defined( 'NONCE_SALT' ) ) {
1366 $cookie_salt = sha1( sha1( 'mainwp' . LOGGED_IN_SALT . $website->id ) . NONCE_SALT . 'WP_Cookie' ); // NOSONAR - safe for salt file name.
1367 } else {
1368 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' ); // NOSONAR - safe for salt file name.
1369 }
1370 $cookieFile = $cookieDir . '/' . $cookie_salt;
1371 if ( ! file_exists( $cookieFile ) ) {
1372 @file_put_contents( $cookieFile, '' );
1373 }
1374
1375 if ( file_exists( $cookieFile ) ) {
1376 @chmod( $cookieFile, 0644 ); // NOSONAR - correct file permissions, owner: rwe, group & others: r.
1377 curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookieFile );
1378 curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookieFile );
1379 }
1380 }
1381
1382 curl_setopt( $ch, CURLOPT_URL, $url );
1383 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
1384 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
1385 curl_setopt( $ch, CURLOPT_POST, true );
1386 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
1387 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
1388 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1389 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1390
1391 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
1392 $http_pass = stripslashes( $http_pass );
1393 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
1394 }
1395
1396 $ssl_verifyhost = false;
1397 if ( null !== $verifyCertificate ) {
1398 if ( 1 === (int) $verifyCertificate ) {
1399 $ssl_verifyhost = true;
1400 } elseif ( 2 === (int) $verifyCertificate ) {
1401 if ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) {
1402 $ssl_verifyhost = true;
1403 }
1404 }
1405 } elseif ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) {
1406 $ssl_verifyhost = true;
1407 }
1408
1409 if ( $ssl_verifyhost ) {
1410 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
1411 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
1412 } else {
1413 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); // NOSONAR.
1414 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // NOSONAR.
1415 }
1416
1417 curl_setopt( $ch, CURLOPT_SSLVERSION, $sslVersion );
1418
1419 if ( is_object( $website ) && property_exists( $website, 'id' ) ) {
1420 $http_version = apply_filters( 'mainwp_curl_http_version', false, $website->id );
1421 if ( false !== $http_version ) {
1422 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
1423 }
1424 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, $website->id, $website->url );
1425 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
1426 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
1427 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
1428 }
1429 }
1430
1431 $headers = array( 'X-Requested-With' => 'XMLHttpRequest' );
1432 $headers['Expect'] = static::get_expect_header( $postdata );
1433
1434 if ( class_exists( '\WpOrg\Requests\Requests' ) ) {
1435 $headers = \WpOrg\Requests\Requests::flatten( $headers );
1436 } else {
1437 $headers = \Requests::flatten( $headers );
1438 }
1439
1440 curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
1441 curl_setopt( $ch, CURLOPT_REFERER, get_option( 'siteurl' ) );
1442
1443 $force_use_ipv4 = false;
1444 $forceUseIPv4 = isset( $others['force_use_ipv4'] ) ? (int) $others['force_use_ipv4'] : null;
1445 if ( null !== $forceUseIPv4 ) {
1446 if ( 1 === $forceUseIPv4 ) {
1447 $force_use_ipv4 = true;
1448 } elseif ( 2 === $forceUseIPv4 ) {
1449 if ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
1450 $force_use_ipv4 = true;
1451 }
1452 }
1453 } elseif ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
1454 $force_use_ipv4 = true;
1455 }
1456
1457 if ( $force_use_ipv4 && defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
1458 curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
1459 }
1460
1461 $timeout = 20 * 60 * 60;
1462 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
1463 MainWP_System_Utility::set_time_limit( $timeout );
1464
1465 MainWP_Utility::end_session();
1466
1467 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Executing handlers' );
1468
1469 $disabled_functions = ini_get( 'disable_functions' );
1470 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
1471 $mh = @curl_multi_init();
1472 @curl_multi_add_handle( $mh, $ch );
1473
1474 $lastRun = 0;
1475 do {
1476 if ( 20 < time() - $lastRun ) {
1477 MainWP_System_Utility::set_time_limit( $timeout );
1478 $lastRun = time();
1479 }
1480 @curl_multi_exec( $mh, $running );
1481 while ( $info = @curl_multi_info_read( $mh ) ) {
1482 $data = @curl_multi_getcontent( $info['handle'] );
1483
1484 $http_status = @curl_getinfo( $info['handle'], CURLINFO_HTTP_CODE );
1485 $err = @curl_error( $info['handle'] );
1486 $real_url = @curl_getinfo( $info['handle'], CURLINFO_EFFECTIVE_URL );
1487
1488 @curl_multi_remove_handle( $mh, $info['handle'] );
1489 }
1490 usleep( 10000 );
1491 } while ( $running > 0 );
1492 if ( 'resource' === gettype( $mh ) ) {
1493 @curl_multi_close( $mh );
1494 }
1495 } else {
1496 $data = @curl_exec( $ch );
1497 $http_status = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1498 $err = @curl_error( $ch );
1499 $real_url = @curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
1500 }
1501
1502 $host = wp_parse_url( $real_url, PHP_URL_HOST );
1503 $ip = gethostbyname( $host );
1504
1505 if ( null !== $website ) {
1506 MainWP_DB_Common::instance()->insert_or_update_request_log( $website->id, $ip, null, microtime( true ) );
1507 }
1508
1509 $raw_response = isset( $others['raw_response'] ) && 'yes' === $others['raw_response'] ? true : false;
1510
1511 $output['fetch_data'] = $data;
1512 $output['http_status'] = (int) $http_status;
1513
1514 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'http status: [' . $http_status . '] err: [' . $err . ']' );
1515 if ( '400' === $http_status ) {
1516 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'post data: [' . MainWP_Utility::value_to_string( $postdata, 1 ) . ']' );
1517 }
1518
1519 MainWP_Logger::instance()->log_execution_time( 'fetch_url_site :: [url=' . $url . ']' );
1520
1521 $thr_error = null;
1522
1523 if ( ( false === $data ) && empty( $http_status ) ) {
1524 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=0][' . $err . ']' );
1525 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1526 } elseif ( empty( $data ) && ! empty( $err ) ) {
1527 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=' . $http_status . '][' . $err . ']' );
1528 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1529 } elseif ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) ) {
1530 $result = $results[1];
1531 $information = MainWP_System_Utility::get_child_response( base64_decode( $result ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
1532 unset( $output['fetch_data'] ); // hide the data.
1533 $pdt = is_string( $postdata ) ? $postdata : '';
1534 $data_log = is_array( $postdata ) ? print_r( $postdata, true ) : $pdt; //phpcs:ignore -- good.
1535 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', '[' . $url . '] postdata [' . $data_log . '] information: [OK]' ); //phpcs:ignore -- ok.
1536 return $information;
1537 } elseif ( 200 === (int) $http_status && ! empty( $err ) ) {
1538 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1539 } elseif ( $raw_response ) {
1540 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Response: [RAW]' );
1541 return $data;
1542 } else {
1543 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] Error: NOMAINWP [data=' . ( is_string( $data ) ? $data : 'OBJECT' ) . ']' );
1544 $detect_wsidchk = is_string( $data ) ? strpos( $data, 'wsidchk' ) : false;
1545 if ( false !== $detect_wsidchk ) {
1546 $thr_error = new MainWP_Exception( 'ERROR:Connection Failed. We suspect that Imunify360, a security layer added by your host, is causing this problem. Please contact your host to whitelist your Dashboard IP in their system. If you need help determining your MainWP Dashboard site IP address, check with your hosting provider.', $url );
1547 } else {
1548 $thr_error = new MainWP_Exception( 'NOMAINWP', $url ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1549 }
1550 }
1551
1552 if ( null !== $thr_error ) {
1553 $thr_error->set_data( $data );
1554 throw $thr_error;
1555 }
1556 }
1557
1558 /**
1559 * Method check_constraints()
1560 *
1561 * Check connection delay constraints.
1562 *
1563 * @param mixed $identifier Lock identifier.
1564 * @param mixed $website Object child site.
1565 *
1566 * @uses \MainWP\Dashboard\MainWP_DB_Common::close_open_requests()
1567 * @uses \MainWP\Dashboard\MainWP_DB::get_wp_ip()
1568 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
1569 */
1570 private static function check_constraints( &$identifier, $website ) { // phpcs:ignore -- NOSONAR -Current complexity is the only way to achieve desired results, pull request solutions appreciated.
1571 $semLock = '103218';
1572 $identifier = static::get_lock_identifier( $semLock );
1573 $minimumDelay = ( ( false === get_option( 'mainwp_minimumDelay' ) ) ? 200 : get_option( 'mainwp_minimumDelay' ) );
1574 if ( 0 < $minimumDelay ) {
1575 $minimumDelay = $minimumDelay / 1000;
1576 }
1577 $minimumIPDelay = ( ( false === get_option( 'mainwp_minimumIPDelay' ) ) ? 1000 : get_option( 'mainwp_minimumIPDelay' ) );
1578 if ( 0 < $minimumIPDelay ) {
1579 $minimumIPDelay = $minimumIPDelay / 1000;
1580 }
1581
1582 MainWP_Utility::end_session();
1583 $delay = true;
1584 while ( $delay ) {
1585 static::lock( $identifier );
1586 if ( 0 < $minimumDelay && static::check_constraints_last_request( $identifier, $minimumDelay ) ) {
1587 continue;
1588 }
1589
1590 if ( 0 < $minimumIPDelay && null !== $website ) {
1591 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1592 if ( null !== $ip && '' !== $ip && static::check_constraints_last_request( $identifier, $minimumIPDelay, $ip ) ) {
1593 continue;
1594 }
1595 }
1596 $delay = false;
1597 }
1598
1599 $maximumRequests = ( ( false === get_option( 'mainwp_maximumRequests' ) ) ? 4 : get_option( 'mainwp_maximumRequests' ) );
1600 $maximumIPRequests = ( ( false === get_option( 'mainwp_maximumIPRequests' ) ) ? 1 : get_option( 'mainwp_maximumIPRequests' ) );
1601
1602 $first = true;
1603 $delay = true;
1604 while ( $delay ) {
1605 if ( ! $first ) {
1606 static::lock( $identifier );
1607 } else {
1608 $first = false;
1609 }
1610
1611 MainWP_DB_Common::instance()->close_open_requests();
1612
1613 if ( 0 < $maximumRequests && static::check_constraints_open_requests( $identifier, $maximumRequests ) ) {
1614 continue;
1615 }
1616
1617 if ( 0 < $maximumIPRequests && null !== $website ) {
1618 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1619 if ( null !== $ip && '' !== $ip && static::check_constraints_open_requests( $identifier, $maximumIPRequests, $ip ) ) {
1620 continue;
1621 }
1622 }
1623 $delay = false;
1624 }
1625 }
1626
1627 /**
1628 * Method check_constraints_last_request().
1629 *
1630 * Check constraints for last requests.
1631 *
1632 * @param mixed $identifier connect identifier.
1633 * @param int $minimumDelay minimum delay.
1634 * @param string|null $ip ip address.
1635 *
1636 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_last_request_timestamp()
1637 */
1638 private static function check_constraints_last_request( $identifier, $minimumDelay, $ip = null ) {
1639 $lastRequest = MainWP_DB_Common::instance()->get_last_request_timestamp( $ip );
1640 if ( $lastRequest > ( ( microtime( true ) ) - $minimumDelay ) ) {
1641 static::release( $identifier );
1642 $sleep = ( $minimumDelay - ( ( microtime( true ) ) - $lastRequest ) ) * 1000 * 1000;
1643 $sleep = intval( $sleep );
1644 usleep( $sleep );
1645 return true;
1646 }
1647 return false;
1648 }
1649
1650 /**
1651 * Method check_constraints_open_requests().
1652 *
1653 * Check constraints for open requests.
1654 *
1655 * @param mixed $identifier connect identifier.
1656 * @param int $maximumRequests maximum requests.
1657 * @param string|null $ip ip address.
1658 *
1659 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_nrof_open_requests()
1660 */
1661 private static function check_constraints_open_requests( $identifier, $maximumRequests, $ip = null ) {
1662 $nrOfOpenRequests = MainWP_DB_Common::instance()->get_nrof_open_requests( $ip );
1663 if ( $nrOfOpenRequests >= $maximumRequests ) {
1664 static::release( $identifier );
1665 usleep( 200000 );
1666 return true;
1667 }
1668 return false;
1669 }
1670
1671 /**
1672 * Method download_to_file()
1673 *
1674 * Download to file.
1675 *
1676 * @param mixed $url Download URL.
1677 * @param mixed $file File to download to.
1678 * @param bool $size Size of file.
1679 * @param null $http_user htaccess username.
1680 * @param null $http_pass htaccess password.
1681 *
1682 * @throws MainWP_Exception Exception message.
1683 *
1684 * @uses \MainWP\Dashboard\MainWP_Exception
1685 * @uses \MainWP\Dashboard\MainWP_System::$version
1686 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1687 */
1688 public static function download_to_file( $url, $file, $size = false, $http_user = null, $http_pass = null ) { // phpcs:ignore -- NOSONAR - complex.
1689
1690 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1691
1692 /**
1693 * WordPress files system object.
1694 *
1695 * @global object
1696 */
1697 global $wp_filesystem;
1698
1699 if ( $wp_filesystem->exists( $file ) && ( ( false === $size ) || ( $wp_filesystem->size( $file ) > $size ) ) ) {
1700 $wp_filesystem->delete( $file );
1701 }
1702
1703 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1704 $wp_filesystem->mkdir( dirname( $file ), 0777 );
1705 }
1706
1707 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1708 throw new MainWP_Exception( esc_html__( 'MainWP plugin could not create directory in order to download the file.', 'mainwp' ) );
1709 }
1710
1711 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1712 if ( ! $wp_filesystem->is_writable( @dirname( $file ) ) ) {
1713 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1714 }
1715 } elseif ( ! is_writable( @dirname( $file ) ) ) { //phpcs:ignore -- ok.
1716 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1717 }
1718
1719 $fp = fopen( $file, 'a' );
1720 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1721 if ( false !== $size && $wp_filesystem->exists( $file ) ) {
1722 $size = $wp_filesystem->size( $file );
1723 $url .= '&foffset=' . $size;
1724 }
1725 $ch = curl_init( str_replace( ' ', '%20', $url ) );
1726
1727 $proxy = new \WP_HTTP_Proxy();
1728 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1729 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1730 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1731 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1732
1733 if ( $proxy->use_authentication() ) {
1734 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1735 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1736 }
1737 }
1738 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1739 curl_setopt( $ch, CURLOPT_HEADER, false );
1740 curl_setopt( $ch, CURLOPT_FILE, $fp );
1741
1742 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1743 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1744
1745 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
1746 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
1747 $http_pass = stripslashes( $http_pass );
1748 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
1749 }
1750 curl_exec( $ch );
1751 if ( 'resource' === gettype( $ch ) ) {
1752 curl_close( $ch );
1753 }
1754 fclose( $fp );
1755 }
1756
1757 /**
1758 * Method init_coockiesdir()
1759 *
1760 * Check for cookies directory and create it if it doesn't already exist,
1761 * set the file permissions and update htaccess.
1762 *
1763 * @param mixed $cookieDir Cookies directory.
1764 *
1765 * @return void
1766 *
1767 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1768 */
1769 public static function init_cookiesdir( $cookieDir ) {
1770
1771 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1772
1773 /**
1774 * WordPress files system object.
1775 *
1776 * @global object
1777 */
1778 global $wp_filesystem;
1779
1780 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1781
1782 if ( ! $wp_filesystem->is_dir( $cookieDir ) ) {
1783 $wp_filesystem->mkdir( $cookieDir, 0777 );
1784 }
1785
1786 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1787 $file_htaccess = $cookieDir . '/.htaccess';
1788 $wp_filesystem->put_contents( $file_htaccess, 'deny from all' );
1789 }
1790
1791 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1792 $file_index = $cookieDir . '/index.php';
1793 $wp_filesystem->touch( $file_index );
1794 }
1795 } else {
1796
1797 if ( ! file_exists( $cookieDir ) ) {
1798 @mkdir( $cookieDir, 0777, true );
1799 }
1800
1801 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1802 $file_htaccess = @fopen( $cookieDir . '/.htaccess', 'w+' );
1803 @fwrite( $file_htaccess, 'deny from all' );
1804 @fclose( $file_htaccess );
1805 }
1806
1807 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1808 $file_index = @fopen( $cookieDir . '/index.php', 'w+' );
1809 @fclose( $file_index );
1810 }
1811 }
1812 }
1813
1814 /**
1815 * Method get_file_content()
1816 *
1817 * Get contents of file.
1818 *
1819 * @param mixed $url File Location.
1820 *
1821 * @return mixed false|$data
1822 *
1823 * @uses \MainWP\Dashboard\MainWP_System::$version
1824 */
1825 public static function get_file_content( $url ) {
1826 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1827 $ch = curl_init();
1828
1829 $proxy = new \WP_HTTP_Proxy();
1830 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1831 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1832 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1833 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1834
1835 if ( $proxy->use_authentication() ) {
1836 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1837 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1838 }
1839 }
1840
1841 curl_setopt( $ch, CURLOPT_HEADER, 0 );
1842 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1843 curl_setopt( $ch, CURLOPT_URL, $url );
1844 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1845 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1846
1847 $data = @curl_exec( $ch );
1848 $httpCode = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1849 if ( 'resource' === gettype( $ch ) ) {
1850 curl_close( $ch );
1851 }
1852 if ( 200 === (int) $httpCode ) {
1853 return $data;
1854 } else {
1855 return false;
1856 }
1857 }
1858
1859 /**
1860 * Method get_favico_url()
1861 *
1862 * Get Child Site favicon URL.
1863 *
1864 * @param mixed $website Child Site info.
1865 *
1866 * @return mixed $faviurl Favicon URL.
1867 *
1868 * @uses \MainWP\Dashboard\MainWP_DB::get_website_option()
1869 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_icons_dir()
1870 * @uses \MainWP\Dashboard\MainWP_Utility::remove_http_prefix()
1871 */
1872 public static function get_favico_url( $website ) {
1873 $favi = MainWP_DB::instance()->get_website_option( $website, 'favi_icon', '' );
1874 $faviurl = '';
1875
1876 if ( ! empty( $favi ) ) {
1877 if ( false !== strpos( $favi, 'favi-' . intval( $website->id ) . '-' ) ) {
1878 $dirs = MainWP_System_Utility::get_icons_dir();
1879 if ( file_exists( $dirs[0] . $favi ) ) {
1880 $faviurl = $dirs[1] . $favi;
1881 } else {
1882 $faviurl = '';
1883 }
1884 } elseif ( ( 0 === strpos( $favi, '//' ) ) || ( 0 === strpos( $favi, 'http' ) ) ) {
1885 $faviurl = $favi;
1886 } else {
1887 $faviurl = $website->url . $favi;
1888 $faviurl = MainWP_Utility::remove_http_prefix( $faviurl );
1889 }
1890 }
1891
1892 if ( empty( $faviurl ) ) {
1893 $faviurl = false;
1894 }
1895
1896 return $faviurl;
1897 }
1898 }
1899