PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 5.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v5.2.2
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.2.2, at class/class-mainwp-connect.php

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