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

1,903 lines 62.2 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 {
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 -- 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'] = self::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 ) {
135 if ( defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
136 curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
137 }
138 }
139
140 $disabled_functions = ini_get( 'disable_functions' );
141 if ( empty( $disabled_functions ) || ( stristr( $disabled_functions, 'curl_multi_exec' ) === false ) ) {
142 $mh = curl_multi_init();
143 @curl_multi_add_handle( $mh, $ch );
144
145 do {
146 curl_multi_exec( $mh, $running );
147 while ( $info = curl_multi_info_read( $mh ) ) {
148 $data = curl_multi_getcontent( $info['handle'] );
149 $err = curl_error( $info['handle'] );
150 $http_status = curl_getinfo( $info['handle'], CURLINFO_HTTP_CODE );
151 $errno = curl_errno( $info['handle'] );
152 $realurl = curl_getinfo( $info['handle'], CURLINFO_EFFECTIVE_URL );
153
154 curl_multi_remove_handle( $mh, $info['handle'] );
155 }
156 usleep( 10000 );
157 } while ( $running > 0 );
158
159 if ( 'resource' === gettype( $mh ) ) {
160 curl_multi_close( $mh );
161 }
162 } else {
163 $data = curl_exec( $ch );
164 $err = curl_error( $ch );
165 $http_status = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
166 $errno = curl_errno( $ch );
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 self::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 -- 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 = self::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 ) ) {
389 if ( is_object( $current_user ) && property_exists( $current_user, 'ID' ) && $current_user->ID ) {
390
391 /**
392 * Filter: mainwp_alter_login_user
393 *
394 * Filters users accounts so it allows you user to jump to child site under alternative administrator account.
395 *
396 * @param int $website->id Child site ID.
397 * @param int $current_user->ID User ID.
398 *
399 * @since Unknown
400 */
401 $alter_user = apply_filters( 'mainwp_alter_login_user', false, $website->id, $current_user->ID );
402 if ( ! empty( $alter_user ) ) {
403 $data['alt_user'] = rawurlencode( $alter_user );
404 }
405 }
406 }
407
408 return http_build_query( $data, '', '&' );
409 }
410
411 return null;
412 }
413
414 /**
415 * Method get_renew_post_data_authed()
416 *
417 * Get authorized $_POST data & build query for renew connection action only.
418 *
419 * @param mixed $website Array of Child Site Info.
420 * @param mixed $what What we are posting.
421 *
422 * @return mixed null|http_build_query()
423 */
424 private static function get_renew_post_data_authed( &$website, $what ) {
425
426 if ( $website && '' !== $what ) {
427 $compat_what = 'disconnect'; // to compatible, renew will call disconnect.
428 $data = array();
429 $data['user'] = $website->adminname;
430 $data['function'] = $compat_what;
431 $data['nonce'] = wp_rand( 0, 9999 );
432
433 $alg = false;
434 $sign_success = null;
435 $use_seclib = false;
436
437 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
438 // to disconnect.
439 $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.
440 $use_seclib = true;
441 } elseif ( function_exists( 'openssl_verify' ) ) {
442 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
443 $sign_success = self::connect_sign( $compat_what . $data['nonce'], $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for keys encoding.
444 if ( empty( $sign_success ) ) { // error from openssl, openssl_sign().
445 $alg = defined( 'OPENSSL_ALGO_SHA1' ) ? OPENSSL_ALGO_SHA1 : false; // to set default SHA1, to disconnect.
446 MainWP_Logger::instance()->debug_for_website( $website, 'get_renew_post_data_authed', '[' . $website->url . '] :: [openssl_sign:failed] :: Set sign_algo=SHA1' );
447 $sign_success = self::connect_sign( $compat_what . $data['nonce'], $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for keys encoding.
448 }
449
450 if ( false !== $alg ) {
451 $data['sign_algo'] = $alg;
452 }
453 }
454
455 if ( $use_seclib ) {
456 $data['verifylib'] = 1;
457 }
458
459 if ( null !== $sign_success && empty( $sign_success ) ) {
460 $sign_error = '';
461 while ( $msg = openssl_error_string() ) {
462 if ( is_string( $msg ) ) {
463 $sign_error .= $msg;
464 }
465 }
466 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 );
467 }
468
469 $data['mainwpsignature'] = ! empty( $signature ) ? base64_encode( $signature ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
470
471 return http_build_query( $data, '', '&' );
472 }
473 return null;
474 }
475
476
477 /**
478 * Method get_get_data_authed()
479 *
480 * Get authorized $_GET data & build query.
481 *
482 * @param mixed $website Child Site data.
483 * @param mixed $paramValue OpenSSL parameter.
484 * @param string $paramName Parameter name.
485 * @param bool $asArray true|false Default is false.
486 * @param array $other_params other params.
487 *
488 * @return string $url
489 */
490 public static function get_get_data_authed( $website, $paramValue, $paramName = 'where', $asArray = false, $other_params = array() ) { //phpcs:ignore -- complex method.
491 $params = array();
492 if ( $website && '' !== $paramValue ) {
493
494 $sign_success = null;
495 $alg = false;
496 $use_seclib = false;
497 $nonce = wp_rand( 0, 9999 );
498 if ( MainWP_Connect_Lib::is_use_fallback_sec_lib( $website ) ) {
499 $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.
500 $use_seclib = true;
501 } elseif ( function_exists( 'openssl_verify' ) ) {
502 $alg = MainWP_System_Utility::get_connect_sign_algorithm( $website );
503 $sign_success = self::connect_sign( $paramValue . $nonce, $signature, base64_decode( $website->privkey ), $alg ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
504 }
505
506 $signature = ! empty( $signature ) ? base64_encode( $signature ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
507
508 if ( null !== $sign_success && empty( $sign_success ) ) {
509 $sign_error = '';
510 while ( $msg = openssl_error_string() ) {
511 if ( is_string( $msg ) ) {
512 $sign_error .= $msg;
513 }
514 }
515 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 );
516 }
517
518 $params = array(
519 'login_required' => 1,
520 'user' => rawurlencode( $website->adminname ),
521 'mainwpsignature' => rawurlencode( $signature ),
522 'nonce' => $nonce,
523 $paramName => rawurlencode( $paramValue ),
524 );
525
526 if ( is_array( $other_params ) ) {
527 foreach ( $other_params as $name => $value ) {
528 if ( is_string( $name ) && ! empty( $name ) && is_scalar( $value ) ) {
529 $params[ sanitize_text_field( wp_unslash( $name ) ) ] = rawurlencode( sanitize_text_field( wp_unslash( $value ) ) );
530 }
531 }
532 }
533
534 if ( false !== $alg ) {
535 $params['sign_algo'] = $alg;
536 }
537
538 if ( ! empty( $use_seclib ) ) {
539 $params['verifylib'] = 1;
540 }
541
542 /**
543 * Current user global.
544 *
545 * @global string
546 */
547 global $current_user;
548
549 if ( ( ! defined( 'DOING_CRON' ) || false === DOING_CRON ) && ( ! defined( 'WP_CLI' ) || false === WP_CLI ) ) {
550 if ( $current_user && $current_user->ID ) {
551 /** This filter is documented in ../class/class-mainwp-connect.php */
552 $alter_user = apply_filters( 'mainwp_alter_login_user', false, $website->id, $current_user->ID );
553 if ( ! empty( $alter_user ) ) {
554 $params['alt_user'] = rawurlencode( $alter_user );
555 }
556 }
557 }
558 }
559
560 if ( $asArray ) {
561 return $params;
562 }
563
564 $url = ( isset( $website->url ) && '' !== $website->url ? $website->url : $website->siteurl );
565 $url .= ( substr( $url, - 1 ) !== '/' ? '/' : '' );
566 $url .= '?';
567
568 foreach ( $params as $key => $value ) {
569 $url .= $key . '=' . $value . '&';
570 }
571
572 return rtrim( $url, '&' );
573 }
574
575 /**
576 * Method connect_sign()
577 *
578 * Sign connect.
579 *
580 * @param string $data Data sign.
581 * @param string $signature signature.
582 * @param string $privkey Private key.
583 * @param mixed $algorithm signature algorithm.
584 *
585 * @return bool Success or not.
586 */
587 public static function connect_sign( $data, &$signature, $privkey, $algorithm ) {
588 if ( false === $algorithm ) {
589 return openssl_sign( $data, $signature, $privkey ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
590 } else {
591 return openssl_sign( $data, $signature, $privkey, $algorithm ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
592 }
593 }
594
595 /**
596 * Method get_post_data_not_authed()
597 *
598 * Get not authorized $_POST data.
599 *
600 * @param mixed $url Child site URL.
601 * @param mixed $admin Admin Username.
602 * @param mixed $what What function to perform.
603 * @param null $params Function parameters.
604 *
605 * @return mixed null|http_build_query()
606 */
607 public static function get_post_data_not_authed( $url, $admin, $what, $params = null ) {
608 if ( '' !== $url && '' !== $admin && '' !== $what ) {
609 $data = array();
610 $data['user'] = $admin;
611 $data['function'] = $what;
612 if ( null !== $params ) {
613 $data = array_merge( $data, $params );
614 }
615
616 return http_build_query( $data, '', '&' );
617 }
618
619 return null;
620 }
621
622 /**
623 * Method fetch_urls_authed()
624 *
625 * Fetch authorized URLs.
626 *
627 * @param object $websites Websites information.
628 * @param string $what Action to perform.
629 * @param array $params Request parameters.
630 * @param mixed $handler Request handler.
631 * @param mixed $output Request output.
632 * @param mixed $whatPage Request URL. Default /admin-ajax.php.
633 * @param array $others Request additional information.
634 *
635 * @return bool true|false
636 *
637 * @uses \MainWP\Dashboard\MainWP_System::$version
638 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
639 */
640 public static function fetch_urls_authed( &$websites, $what, $params, $handler, &$output, $whatPage = null, $others = array() ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity -- complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
641
642 if ( ! is_array( $websites ) || empty( $websites ) ) {
643 return false;
644 }
645
646 if ( ! is_array( $params ) ) {
647 $params = array();
648 }
649
650 $chunkSize = apply_filters( 'mainwp_fetch_urls_chunk_size', 10 );
651 if ( count( $websites ) > $chunkSize ) {
652 $total = count( $websites );
653 $loops = ceil( $total / $chunkSize );
654 for ( $i = 0; $i < $loops; $i++ ) {
655 $newSites = array_slice( $websites, $i * $chunkSize, $chunkSize, true );
656 self::fetch_urls_authed( $newSites, $what, $params, $handler, $output, $whatPage, $others );
657 sleep( 5 );
658 }
659
660 return false;
661 }
662
663 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
664 $mh = curl_multi_init();
665
666 $timeout = 20 * 60 * 60;
667
668 $disabled_functions = ini_get( 'disable_functions' );
669 $handleToWebsite = array();
670 $requestUrls = array();
671 $requestHandles = array();
672
673 $dirs = MainWP_System_Utility::get_mainwp_dir();
674 $cookieDir = $dirs[0] . 'cookies';
675
676 self::init_cookiesdir( $cookieDir );
677
678 $_org_params = null;
679
680 foreach ( $websites as $website ) {
681
682 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
683 MainWP_Demo_Handle::get_instance()->handle_fetch_urls_demo( $data, $website, $output, $what, $params );
684 continue;
685 }
686
687 $url = $website->url;
688 if ( '/' !== substr( $url, - 1 ) ) {
689 $url .= '/';
690 }
691
692 if ( false === strpos( $url, 'wp-admin' ) ) {
693 $url .= 'wp-admin/';
694 }
695
696 if ( null !== $whatPage ) {
697 $url .= $whatPage;
698 } else {
699 $url .= 'admin-ajax.php';
700 }
701
702 if ( property_exists( $website, 'http_user' ) ) {
703 $http_user = $website->http_user;
704 }
705 if ( property_exists( $website, 'http_pass' ) ) {
706 $http_pass = $website->http_pass;
707 }
708
709 if ( isset( $params ) && isset( $params['new_post'] ) ) {
710
711 if ( null === $_org_params ) {
712 $_org_params = $params;
713 }
714
715 /**
716 * Filter is being replaced with mainwp_pre_posting_posts.
717 *
718 * @deprecated
719 */
720 $params = apply_filters_deprecated(
721 'mainwp-pre-posting-posts',
722 array(
723 ( is_array( $params ) ? $params : array() ),
724 (object) array(
725 'id' => $website->id,
726 'url' => $website->url,
727 'name' => $website->name,
728 ),
729 ),
730 '4.0.7.2',
731 'mainwp_pre_posting_posts'
732 );
733
734 /**
735 * Filter: mainwp_pre_posting_posts
736 *
737 * Prepares parameters for the authenticated cURL post.
738 *
739 * @since 4.1
740 */
741 $params = apply_filters(
742 'mainwp_pre_posting_posts',
743 ( is_array( $params ) ? $params : array() ),
744 (object) array(
745 'id' => $website->id,
746 'url' => $website->url,
747 'name' => $website->name,
748 )
749 );
750 }
751
752 $ch = curl_init();
753
754 $proxy = new \WP_HTTP_Proxy();
755 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
756 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
757 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
758 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
759
760 if ( $proxy->use_authentication() ) {
761 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
762 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
763 }
764 }
765
766 if ( ( null !== $website ) && ( ( property_exists( $website, 'wpe' ) && 1 !== $website->wpe ) || ( isset( $others['upgrade'] ) && ( true === $others['upgrade'] ) ) ) ) {
767 // to fix.
768 if ( defined( 'LOGGED_IN_SALT' ) && defined( 'NONCE_SALT' ) ) {
769 $cookie_salt = sha1( sha1( 'mainwp' . LOGGED_IN_SALT . $website->id ) . NONCE_SALT . 'WP_Cookie' );
770 } else {
771 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' );
772 }
773 $cookieFile = $cookieDir . '/' . $cookie_salt;
774 if ( ! file_exists( $cookieFile ) ) {
775 @file_put_contents( $cookieFile, '' );
776 }
777
778 if ( file_exists( $cookieFile ) ) {
779 @chmod( $cookieFile, 0644 );
780 curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookieFile );
781 curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookieFile );
782 }
783 }
784
785 curl_setopt( $ch, CURLOPT_URL, $url );
786 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
787 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
788 curl_setopt( $ch, CURLOPT_POST, true );
789
790 $postdata = self::get_post_data_authed( $website, $what, $params );
791 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
792 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
793 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
794 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
795 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
796 $http_pass = stripslashes( $http_pass );
797 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
798 }
799
800 $ssl_verifyhost = false;
801 $verifyCertificate = isset( $website->verify_certificate ) ? (int) $website->verify_certificate : null;
802 if ( null !== $verifyCertificate ) {
803 if ( 1 === $verifyCertificate ) {
804 $ssl_verifyhost = true;
805 } elseif ( 2 === $verifyCertificate ) {
806 if ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
807 $ssl_verifyhost = true;
808 }
809 }
810 } elseif ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
811 $ssl_verifyhost = true;
812 }
813
814 if ( $ssl_verifyhost ) {
815 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
816 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
817 } else {
818 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false ); // NOSONAR .
819 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false ); // NOSONAR .
820 }
821
822 curl_setopt( $ch, CURLOPT_SSLVERSION, $website->ssl_version );
823
824 if ( is_object( $website ) && property_exists( $website, 'id' ) ) {
825 $http_version = apply_filters( 'mainwp_curl_http_version', false, $website->id );
826 if ( false !== $http_version ) {
827 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
828 }
829
830 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, $website->id, $website->url );
831 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
832 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
833 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
834 }
835 }
836
837 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
838 MainWP_System_Utility::set_time_limit( $timeout );
839
840 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
841 @curl_multi_add_handle( $mh, $ch );
842 }
843
844 $handleToWebsite[ self::get_resource_id( $ch ) ] = $website;
845 $requestUrls[ self::get_resource_id( $ch ) ] = $website->url;
846 $requestHandles[ self::get_resource_id( $ch ) ] = $ch;
847
848 if ( null !== $_org_params ) {
849 $params = $_org_params;
850 }
851 }
852
853 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
854 $lastRun = 0;
855 do {
856 if ( 20 < time() - $lastRun ) {
857 MainWP_System_Utility::set_time_limit( $timeout );
858 $lastRun = time();
859 }
860
861 curl_multi_exec( $mh, $running );
862 while ( $info = curl_multi_info_read( $mh ) ) {
863 $data = curl_multi_getcontent( $info['handle'] );
864 $contains = ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) );
865 curl_multi_remove_handle( $mh, $info['handle'] );
866
867 if ( ! $contains && isset( $requestUrls[ self::get_resource_id( $info['handle'] ) ] ) ) {
868 curl_setopt( $info['handle'], CURLOPT_URL, $requestUrls[ self::get_resource_id( $info['handle'] ) ] );
869 curl_multi_add_handle( $mh, $info['handle'] );
870 unset( $requestUrls[ self::get_resource_id( $info['handle'] ) ] );
871 ++$running;
872 continue;
873 }
874
875 if ( null !== $handler ) {
876 $site = &$handleToWebsite[ self::get_resource_id( $info['handle'] ) ];
877 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
878 }
879
880 unset( $handleToWebsite[ self::get_resource_id( $info['handle'] ) ] );
881 if ( 'resource' === gettype( $info['handle'] ) ) {
882 curl_close( $info['handle'] );
883 }
884 unset( $info['handle'] );
885 }
886 usleep( 10000 );
887 } while ( $running > 0 );
888
889 if ( 'resource' === gettype( $mh ) ) {
890 curl_multi_close( $mh );
891 }
892 } else {
893 foreach ( $requestHandles as $id => $ch ) {
894 $data = curl_exec( $ch );
895
896 if ( null !== $handler ) {
897 $site = &$handleToWebsite[ self::get_resource_id( $ch ) ];
898 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
899 }
900 }
901 }
902
903 return true;
904 }
905
906 /**
907 * Credits WordPress org.
908 *
909 * Get the correct "Expect" header for the given request data.
910 *
911 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
912 * @return string The "Expect" header.
913 */
914 protected static function get_expect_header( $data ) {
915 if ( ! is_array( $data ) ) {
916 return strlen( (string) $data ) >= 1048576 ? '100-Continue' : '';
917 }
918
919 $bytesize = 0;
920 $iterator = new \RecursiveIteratorIterator( new \RecursiveArrayIterator( $data ) );
921
922 foreach ( $iterator as $datum ) {
923 $bytesize += strlen( (string) $datum );
924
925 if ( $bytesize >= 1048576 ) {
926 return '100-Continue';
927 }
928 }
929
930 return '';
931 }
932
933 /**
934 * Method get_resource_id()
935 *
936 * Get resource id.
937 *
938 * @param mixed $res The given resource.
939 *
940 * @return $result Resource ID only.
941 */
942 public static function get_resource_id( $res ) {
943 $result = false;
944 if ( is_a( $res, 'CurlHandle' ) ) {
945 $result = spl_object_hash( $res );
946 } elseif ( is_resource( $res ) ) {
947 $resourceString = (string) $res;
948 $exploded = explode( '#', $resourceString );
949 $result = array_pop( $exploded );
950 }
951 return $result;
952 }
953
954 /**
955 * Method get_lock_identifier().
956 *
957 * Get lock identifier.
958 *
959 * @param mixed $pLockName Provided Lock Name.
960 *
961 * @return mixed false|sem_get()|@fopen
962 */
963 public static function get_lock_identifier( $pLockName ) {
964 if ( ( null === $pLockName ) || ( false === $pLockName ) ) {
965 return false;
966 }
967
968 if ( function_exists( 'sem_get' ) ) {
969 return sem_get( $pLockName );
970 } else {
971 $fh = @fopen( sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'lock' . $pLockName . '.txt', 'w+' );
972 if ( ! $fh ) {
973 return false;
974 }
975
976 return $fh;
977 }
978
979 return false;
980 }
981
982 /**
983 * Method lock()
984 *
985 * Use sem_acquire or @flock to lock the $identifier.
986 *
987 * @param mixed $identifier Identifier.
988 *
989 * @return mixed false|sem_acquire()|@flock
990 */
991 public static function lock( $identifier ) {
992 if ( ( null === $identifier ) || ( false === $identifier ) ) {
993 return false;
994 }
995
996 if ( function_exists( 'sem_acquire' ) ) {
997 return sem_acquire( $identifier );
998 } else {
999 if ( ! is_resource( $identifier ) ) {
1000 return false; // to fix.
1001 }
1002 for ( $i = 0; $i < 3; $i++ ) {
1003 if ( @flock( $identifier, LOCK_EX ) ) {
1004 return $identifier;
1005 } else {
1006 sleep( 1 );
1007 }
1008 }
1009
1010 return false;
1011 }
1012
1013 return false;
1014 }
1015
1016 /**
1017 * Method release()
1018 *
1019 * Use sem_release or @flock, @fclose to unlock $identifier.
1020 *
1021 * @param mixed $identifier Identifier.
1022 *
1023 * @return mixed false|sem_release()|@flock
1024 */
1025 public static function release( $identifier ) {
1026 if ( ( null === $identifier ) || ( false === $identifier ) ) {
1027 return false;
1028 }
1029
1030 if ( function_exists( 'sem_release' ) ) {
1031 return sem_release( $identifier );
1032 } else {
1033 if ( ! is_resource( $identifier ) ) {
1034 return false; // to fix.
1035 }
1036 @flock( $identifier, LOCK_UN );
1037 @fclose( $identifier );
1038 }
1039
1040 return false;
1041 }
1042
1043 /**
1044 * Method fetch_url_authed()
1045 *
1046 * Updates the child site via authenticated request.
1047 *
1048 * @param object $website Website information.
1049 * @param string $what Function to perform.
1050 * @param null $params Function parameters.
1051 * @param bool $checkConstraints Whether or not to check constraints.
1052 * @param bool $pForceFetch Whether or not to force the fetch.
1053 * @param bool $pRetryFailed Whether or not to retry the fetch process.
1054 * @param null $rawResponse Raw response.
1055 *
1056 * @return mixed $information
1057 *
1058 * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::handle_check_website()
1059 * @uses \MainWP\Dashboard\MainWP_Premium_Update::maybe_request_premium_updates()
1060 * @uses \MainWP\Dashboard\MainWP_Sync::sync_information_array()
1061 */
1062 public static function fetch_url_authed(
1063 &$website,
1064 $what,
1065 $params = null,
1066 $checkConstraints = false,
1067 $pForceFetch = false,
1068 $pRetryFailed = true,
1069 $rawResponse = null
1070 ) {
1071
1072 // to support demo data.
1073 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
1074 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $website, $what );
1075 }
1076
1077 if ( ! is_array( $params ) ) {
1078 $params = array();
1079 }
1080
1081 $others = array(
1082 'force_use_ipv4' => $website->force_use_ipv4,
1083 'upgrade' => ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ),
1084 );
1085
1086 $request_update = MainWP_Premium_Update::maybe_request_premium_updates( $website, $what, $params );
1087
1088 if ( isset( $rawResponse ) && $rawResponse ) {
1089 $others['raw_response'] = 'yes';
1090 }
1091
1092 $params['optimize'] = ( ( 1 === (int) get_option( 'mainwp_optimize', 1 ) ) ? 1 : 0 );
1093
1094 $updating_website = false;
1095 $type = '';
1096 $list = '';
1097 if ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ) {
1098 $updating_website = true;
1099 if ( 'upgradeplugintheme' === $what || 'upgradetranslation' === $what ) {
1100 $type = $params['type'];
1101 $list = $params['list'];
1102 } else {
1103 $type = 'wp';
1104 $list = '';
1105 }
1106 }
1107
1108 if ( $updating_website ) {
1109 /**
1110 * Action: mainwp_website_before_updated
1111 *
1112 * Fires before the child site update process.
1113 *
1114 * @param object $website Object containing child site info.
1115 * @param string $type Type parameter.
1116 * @param string $list List parameter.
1117 *
1118 * @since Unknown
1119 */
1120 do_action( 'mainwp_website_before_updated', $website, $type, $list );
1121 }
1122
1123 if ( 'renew' === $what ) {
1124 $postdata = self::get_renew_post_data_authed( $website, $what );
1125 } else {
1126 $postdata = self::get_post_data_authed( $website, $what, $params );
1127
1128 }
1129 $others['function'] = $what;
1130
1131 $information = array();
1132
1133 if ( ! $request_update ) {
1134 $information = self::fetch_url( $website, $website->url, $postdata, $checkConstraints, $website->verify_certificate, $pRetryFailed, $website->http_user, $website->http_pass, $website->ssl_version, $others );
1135 /**
1136 * Fires immediately after fetch url action.
1137 *
1138 * @param object $website website.
1139 * @param array $information information result data.
1140 * @param string $what action.
1141 * @param array $params params input array.
1142 * @param array $others others input array.
1143 *
1144 * @since 4.5.1.1
1145 */
1146 do_action( 'mainwp_fetch_url_authed', $website, $information, $what, $params, $others );
1147 } else {
1148 $slug = $params['list'];
1149 $information['upgrades'] = array( $slug => 1 );
1150 }
1151
1152 if ( is_array( $information ) && isset( $information['sync'] ) && ! empty( $information['sync'] ) ) {
1153 MainWP_Sync::sync_information_array( $website, $information['sync'] );
1154 unset( $information['sync'] );
1155 }
1156
1157 if ( $updating_website ) {
1158 /**
1159 * Action: mainwp_website_updated
1160 *
1161 * Fires after the child site update process.
1162 *
1163 * @param object $website Object containing child site info.
1164 * @param string $type Type parameter.
1165 * @param string $list List parameter.
1166 * @param array $information Array containing the information fetched from the child site.
1167 *
1168 * @since Unknown
1169 */
1170 do_action( 'mainwp_website_updated', $website, $type, $list, $information );
1171 if ( 1 === (int) get_option( 'mainwp_check_http_response', 0 ) ) {
1172 MainWP_Monitoring_Handler::handle_check_website( $website );
1173 }
1174 }
1175
1176 return $information;
1177 }
1178
1179 /**
1180 * Method fetch_url_not_authed()
1181 *
1182 * Fetch not authorized URL.
1183 *
1184 * @param string $url URL to fetch from.
1185 * @param string $admin Admin name.
1186 * @param string $what Function to perform.
1187 * @param null $params Function parameters.
1188 * @param bool $pForceFetch true|false Whether or not to force the fetch.
1189 * @param null $verifyCertificate Verify the SSL Certificate.
1190 * @param null $http_user htaccess username.
1191 * @param null $http_pass htaccess password.
1192 * @param integer $sslVersion SSL version to check for.
1193 * @param array $others Other functions to perform.
1194 * @param array $output Output values.
1195 *
1196 * @return mixed self::fetch_url() Fetch URL.
1197 */
1198 public static function fetch_url_not_authed(
1199 $url,
1200 $admin,
1201 $what,
1202 $params = null,
1203 $pForceFetch = false,
1204 $verifyCertificate = null,
1205 $http_user = null,
1206 $http_pass = null,
1207 $sslVersion = 0,
1208 $others = array(),
1209 &$output = array()
1210 ) {
1211
1212 if ( empty( $params ) ) {
1213 $params = array();
1214 }
1215
1216 $postdata = self::get_post_data_not_authed( $url, $admin, $what, $params );
1217 $website = null;
1218
1219 $others['function'] = $what;
1220 return self::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 self::fetch_url_site()
1243 */
1244 public static function fetch_url(
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 self::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 self::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 -- 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 self::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 self::release( $identifier );
1342 }
1343
1344 $dirs = MainWP_System_Utility::get_mainwp_dir();
1345 $cookieDir = $dirs[0] . 'cookies';
1346
1347 self::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' );
1367 } else {
1368 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' );
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 );
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'] = self::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 ) {
1458 if ( defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
1459 curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
1460 }
1461 }
1462
1463 $timeout = 20 * 60 * 60;
1464 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
1465 MainWP_System_Utility::set_time_limit( $timeout );
1466
1467 MainWP_Utility::end_session();
1468
1469 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Executing handlers' );
1470
1471 $disabled_functions = ini_get( 'disable_functions' );
1472 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
1473 $mh = @curl_multi_init();
1474 @curl_multi_add_handle( $mh, $ch );
1475
1476 $lastRun = 0;
1477 do {
1478 if ( 20 < time() - $lastRun ) {
1479 MainWP_System_Utility::set_time_limit( $timeout );
1480 $lastRun = time();
1481 }
1482 @curl_multi_exec( $mh, $running );
1483 while ( $info = @curl_multi_info_read( $mh ) ) {
1484 $data = @curl_multi_getcontent( $info['handle'] );
1485
1486 $http_status = @curl_getinfo( $info['handle'], CURLINFO_HTTP_CODE );
1487 $err = @curl_error( $info['handle'] );
1488 $real_url = @curl_getinfo( $info['handle'], CURLINFO_EFFECTIVE_URL );
1489
1490 @curl_multi_remove_handle( $mh, $info['handle'] );
1491 }
1492 usleep( 10000 );
1493 } while ( $running > 0 );
1494 if ( 'resource' === gettype( $mh ) ) {
1495 @curl_multi_close( $mh );
1496 }
1497 } else {
1498 $data = @curl_exec( $ch );
1499 $http_status = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1500 $err = @curl_error( $ch );
1501 $real_url = @curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
1502 }
1503
1504 $host = wp_parse_url( $real_url, PHP_URL_HOST );
1505 $ip = gethostbyname( $host );
1506
1507 if ( null !== $website ) {
1508 MainWP_DB_Common::instance()->insert_or_update_request_log( $website->id, $ip, null, microtime( true ) );
1509 }
1510
1511 $raw_response = isset( $others['raw_response'] ) && 'yes' === $others['raw_response'] ? true : false;
1512
1513 $output['fetch_data'] = $data;
1514 $output['http_status'] = (int) $http_status;
1515
1516 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'http status: [' . $http_status . '] err: [' . $err . ']' );
1517 if ( '400' === $http_status ) {
1518 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'post data: [' . MainWP_Utility::value_to_string( $postdata, 1 ) . ']' );
1519 }
1520
1521 MainWP_Logger::instance()->log_execution_time( 'fetch_url_site :: [url=' . $url . ']' );
1522
1523 $thr_error = null;
1524
1525 if ( ( false === $data ) && empty( $http_status ) ) {
1526 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=0][' . $err . ']' );
1527 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1528 } elseif ( empty( $data ) && ! empty( $err ) ) {
1529 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=' . $http_status . '][' . $err . ']' );
1530 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1531 } elseif ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) ) {
1532 $result = $results[1];
1533 $information = MainWP_System_Utility::get_child_response( base64_decode( $result ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
1534 unset( $output['fetch_data'] ); // hide the data.
1535 $data_log = is_array( $postdata ) ? print_r( $postdata, true ) : ( is_string( $postdata ) ? $postdata : '' ); //phpcs:ignore -- good.
1536 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', '[' . $url . '] postdata [' . $data_log . '] information: [OK]' ); //phpcs:ignore -- ok.
1537 return $information;
1538 } elseif ( 200 === (int) $http_status && ! empty( $err ) ) {
1539 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1540 } elseif ( $raw_response ) {
1541 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Response: [RAW]' );
1542 return $data;
1543 } else {
1544 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] Error: NOMAINWP [data=' . ( is_string( $data ) ? $data : 'OBJECT' ) . ']' );
1545 $detect_wsidchk = is_string( $data ) ? strpos( $data, 'wsidchk' ) : false;
1546 if ( false !== $detect_wsidchk ) {
1547 $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 );
1548 } else {
1549 $thr_error = new MainWP_Exception( 'NOMAINWP', $url ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1550 }
1551 }
1552
1553 if ( null !== $thr_error ) {
1554 $thr_error->set_data( $data );
1555 throw $thr_error;
1556 }
1557 }
1558
1559 /**
1560 * Method check_constraints()
1561 *
1562 * Check connection delay constraints.
1563 *
1564 * @param mixed $identifier Lock identifier.
1565 * @param mixed $website Object child site.
1566 *
1567 * @uses \MainWP\Dashboard\MainWP_DB_Common::close_open_requests()
1568 * @uses \MainWP\Dashboard\MainWP_DB::get_wp_ip()
1569 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
1570 */
1571 private static function check_constraints( &$identifier, $website ) { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
1572 $semLock = '103218';
1573 $identifier = self::get_lock_identifier( $semLock );
1574 $minimumDelay = ( ( false === get_option( 'mainwp_minimumDelay' ) ) ? 200 : get_option( 'mainwp_minimumDelay' ) );
1575 if ( 0 < $minimumDelay ) {
1576 $minimumDelay = $minimumDelay / 1000;
1577 }
1578 $minimumIPDelay = ( ( false === get_option( 'mainwp_minimumIPDelay' ) ) ? 1000 : get_option( 'mainwp_minimumIPDelay' ) );
1579 if ( 0 < $minimumIPDelay ) {
1580 $minimumIPDelay = $minimumIPDelay / 1000;
1581 }
1582
1583 MainWP_Utility::end_session();
1584 $delay = true;
1585 while ( $delay ) {
1586 self::lock( $identifier );
1587 if ( 0 < $minimumDelay && self::check_constraints_last_request( $identifier, $minimumDelay ) ) {
1588 continue;
1589 }
1590
1591 if ( 0 < $minimumIPDelay && null !== $website ) {
1592 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1593 if ( null !== $ip && '' !== $ip ) {
1594 if ( self::check_constraints_last_request( $identifier, $minimumIPDelay, $ip ) ) {
1595 continue;
1596 }
1597 }
1598 }
1599 $delay = false;
1600 }
1601
1602 $maximumRequests = ( ( false === get_option( 'mainwp_maximumRequests' ) ) ? 4 : get_option( 'mainwp_maximumRequests' ) );
1603 $maximumIPRequests = ( ( false === get_option( 'mainwp_maximumIPRequests' ) ) ? 1 : get_option( 'mainwp_maximumIPRequests' ) );
1604
1605 $first = true;
1606 $delay = true;
1607 while ( $delay ) {
1608 if ( ! $first ) {
1609 self::lock( $identifier );
1610 } else {
1611 $first = false;
1612 }
1613
1614 MainWP_DB_Common::instance()->close_open_requests();
1615
1616 if ( 0 < $maximumRequests && self::check_constraints_open_requests( $identifier, $maximumRequests ) ) {
1617 continue;
1618 }
1619
1620 if ( 0 < $maximumIPRequests && null !== $website ) {
1621 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1622 if ( null !== $ip && '' !== $ip ) {
1623 if ( self::check_constraints_open_requests( $identifier, $maximumIPRequests, $ip ) ) {
1624 continue;
1625 }
1626 }
1627 }
1628 $delay = false;
1629 }
1630 }
1631
1632 /**
1633 * Method check_constraints_last_request().
1634 *
1635 * Check constraints for last requests.
1636 *
1637 * @param mixed $identifier connect identifier.
1638 * @param int $minimumDelay minimum delay.
1639 * @param string|null $ip ip address.
1640 *
1641 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_last_request_timestamp()
1642 */
1643 private static function check_constraints_last_request( $identifier, $minimumDelay, $ip = null ) {
1644 $lastRequest = MainWP_DB_Common::instance()->get_last_request_timestamp( $ip );
1645 if ( $lastRequest > ( ( microtime( true ) ) - $minimumDelay ) ) {
1646 self::release( $identifier );
1647 $sleep = ( $minimumDelay - ( ( microtime( true ) ) - $lastRequest ) ) * 1000 * 1000;
1648 $sleep = intval( $sleep );
1649 usleep( $sleep );
1650 return true;
1651 }
1652 return false;
1653 }
1654
1655 /**
1656 * Method check_constraints_open_requests().
1657 *
1658 * Check constraints for open requests.
1659 *
1660 * @param mixed $identifier connect identifier.
1661 * @param int $maximumRequests maximum requests.
1662 * @param string|null $ip ip address.
1663 *
1664 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_nrof_open_requests()
1665 */
1666 private static function check_constraints_open_requests( $identifier, $maximumRequests, $ip = null ) {
1667 $nrOfOpenRequests = MainWP_DB_Common::instance()->get_nrof_open_requests( $ip );
1668 if ( $nrOfOpenRequests >= $maximumRequests ) {
1669 self::release( $identifier );
1670 usleep( 200000 );
1671 return true;
1672 }
1673 return false;
1674 }
1675
1676 /**
1677 * Method download_to_file()
1678 *
1679 * Download to file.
1680 *
1681 * @param mixed $url Download URL.
1682 * @param mixed $file File to download to.
1683 * @param bool $size Size of file.
1684 * @param null $http_user htaccess username.
1685 * @param null $http_pass htaccess password.
1686 *
1687 * @throws MainWP_Exception Exception message.
1688 *
1689 * @uses \MainWP\Dashboard\MainWP_Exception
1690 * @uses \MainWP\Dashboard\MainWP_System::$version
1691 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1692 */
1693 public static function download_to_file( $url, $file, $size = false, $http_user = null, $http_pass = null ) {
1694
1695 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1696
1697 /**
1698 * WordPress files system object.
1699 *
1700 * @global object
1701 */
1702 global $wp_filesystem;
1703
1704 if ( $wp_filesystem->exists( $file ) && ( ( false === $size ) || ( $wp_filesystem->size( $file ) > $size ) ) ) {
1705 $wp_filesystem->delete( $file );
1706 }
1707
1708 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1709 $wp_filesystem->mkdir( dirname( $file ), 0777 );
1710 }
1711
1712 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1713 throw new MainWP_Exception( esc_html__( 'MainWP plugin could not create directory in order to download the file.', 'mainwp' ) );
1714 }
1715
1716 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1717 if ( ! $wp_filesystem->is_writable( @dirname( $file ) ) ) {
1718 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1719 }
1720 } elseif ( ! is_writable( @dirname( $file ) ) ) { //phpcs:ignore -- ok.
1721 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1722 }
1723
1724 $fp = fopen( $file, 'a' );
1725 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1726 if ( false !== $size ) {
1727 if ( $wp_filesystem->exists( $file ) ) {
1728 $size = $wp_filesystem->size( $file );
1729 $url .= '&foffset=' . $size;
1730 }
1731 }
1732 $ch = curl_init( str_replace( ' ', '%20', $url ) );
1733
1734 $proxy = new \WP_HTTP_Proxy();
1735 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1736 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1737 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1738 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1739
1740 if ( $proxy->use_authentication() ) {
1741 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1742 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1743 }
1744 }
1745
1746 curl_setopt( $ch, CURLOPT_FILE, $fp );
1747 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1748 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1749 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
1750 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
1751 $http_pass = stripslashes( $http_pass );
1752 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
1753 }
1754 curl_exec( $ch );
1755 if ( 'resource' === gettype( $ch ) ) {
1756 curl_close( $ch );
1757 }
1758 fclose( $fp );
1759 }
1760
1761 /**
1762 * Method init_coockiesdir()
1763 *
1764 * Check for cookies directory and create it if it doesn't already exist,
1765 * set the file permissions and update htaccess.
1766 *
1767 * @param mixed $cookieDir Cookies directory.
1768 *
1769 * @return void
1770 *
1771 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1772 */
1773 public static function init_cookiesdir( $cookieDir ) {
1774
1775 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1776
1777 /**
1778 * WordPress files system object.
1779 *
1780 * @global object
1781 */
1782 global $wp_filesystem;
1783
1784 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1785
1786 if ( ! $wp_filesystem->is_dir( $cookieDir ) ) {
1787 $wp_filesystem->mkdir( $cookieDir, 0777 );
1788 }
1789
1790 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1791 $file_htaccess = $cookieDir . '/.htaccess';
1792 $wp_filesystem->put_contents( $file_htaccess, 'deny from all' );
1793 }
1794
1795 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1796 $file_index = $cookieDir . '/index.php';
1797 $wp_filesystem->touch( $file_index );
1798 }
1799 } else {
1800
1801 if ( ! file_exists( $cookieDir ) ) {
1802 @mkdir( $cookieDir, 0777, true );
1803 }
1804
1805 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1806 $file_htaccess = @fopen( $cookieDir . '/.htaccess', 'w+' );
1807 @fwrite( $file_htaccess, 'deny from all' );
1808 @fclose( $file_htaccess );
1809 }
1810
1811 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1812 $file_index = @fopen( $cookieDir . '/index.php', 'w+' );
1813 @fclose( $file_index );
1814 }
1815 }
1816 }
1817
1818 /**
1819 * Method get_file_content()
1820 *
1821 * Get contents of file.
1822 *
1823 * @param mixed $url File Location.
1824 *
1825 * @return mixed false|$data
1826 *
1827 * @uses \MainWP\Dashboard\MainWP_System::$version
1828 */
1829 public static function get_file_content( $url ) {
1830 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1831 $ch = curl_init();
1832
1833 $proxy = new \WP_HTTP_Proxy();
1834 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1835 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1836 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1837 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1838
1839 if ( $proxy->use_authentication() ) {
1840 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1841 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1842 }
1843 }
1844
1845 curl_setopt( $ch, CURLOPT_HEADER, 0 );
1846 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1847 curl_setopt( $ch, CURLOPT_URL, $url );
1848 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1849 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1850
1851 $data = @curl_exec( $ch );
1852 $httpCode = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1853 if ( 'resource' === gettype( $ch ) ) {
1854 curl_close( $ch );
1855 }
1856 if ( 200 === (int) $httpCode ) {
1857 return $data;
1858 } else {
1859 return false;
1860 }
1861 }
1862
1863 /**
1864 * Method get_favico_url()
1865 *
1866 * Get Child Site favicon URL.
1867 *
1868 * @param mixed $website Child Site info.
1869 *
1870 * @return mixed $faviurl Favicon URL.
1871 *
1872 * @uses \MainWP\Dashboard\MainWP_DB::get_website_option()
1873 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_icons_dir()
1874 * @uses \MainWP\Dashboard\MainWP_Utility::remove_http_prefix()
1875 */
1876 public static function get_favico_url( $website ) {
1877 $favi = MainWP_DB::instance()->get_website_option( $website, 'favi_icon', '' );
1878 $faviurl = '';
1879
1880 if ( ! empty( $favi ) ) {
1881 if ( false !== strpos( $favi, 'favi-' . intval( $website->id ) . '-' ) ) {
1882 $dirs = MainWP_System_Utility::get_icons_dir();
1883 if ( file_exists( $dirs[0] . $favi ) ) {
1884 $faviurl = $dirs[1] . $favi;
1885 } else {
1886 $faviurl = '';
1887 }
1888 } elseif ( ( 0 === strpos( $favi, '//' ) ) || ( 0 === strpos( $favi, 'http' ) ) ) {
1889 $faviurl = $favi;
1890 } else {
1891 $faviurl = $website->url . $favi;
1892 $faviurl = MainWP_Utility::remove_http_prefix( $faviurl );
1893 }
1894 }
1895
1896 if ( empty( $faviurl ) ) {
1897 $faviurl = false;
1898 }
1899
1900 return $faviurl;
1901 }
1902 }
1903