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

1,899 lines 62.0 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 );
93 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
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 foreach ( $websites as $website ) {
679
680 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
681 MainWP_Demo_Handle::get_instance()->handle_fetch_urls_demo( $data, $website, $output, $what, $params );
682 continue;
683 }
684
685 $url = $website->url;
686 if ( '/' !== substr( $url, - 1 ) ) {
687 $url .= '/';
688 }
689
690 if ( false === strpos( $url, 'wp-admin' ) ) {
691 $url .= 'wp-admin/';
692 }
693
694 if ( null !== $whatPage ) {
695 $url .= $whatPage;
696 } else {
697 $url .= 'admin-ajax.php';
698 }
699
700 if ( property_exists( $website, 'http_user' ) ) {
701 $http_user = $website->http_user;
702 }
703 if ( property_exists( $website, 'http_pass' ) ) {
704 $http_pass = $website->http_pass;
705 }
706
707 $_new_post = null;
708 if ( isset( $params ) && isset( $params['new_post'] ) ) {
709 $_new_post = $params['new_post'];
710
711 /**
712 * Filter is being replaced with mainwp_pre_posting_posts.
713 *
714 * @deprecated
715 */
716 $params = apply_filters_deprecated(
717 'mainwp-pre-posting-posts',
718 array(
719 ( is_array( $params ) ? $params : array() ),
720 (object) array(
721 'id' => $website->id,
722 'url' => $website->url,
723 'name' => $website->name,
724 ),
725 ),
726 '4.0.7.2',
727 'mainwp_pre_posting_posts'
728 );
729
730 /**
731 * Filter: mainwp_pre_posting_posts
732 *
733 * Prepares parameters for the authenticated cURL post.
734 *
735 * @since 4.1
736 */
737 $params = apply_filters(
738 'mainwp_pre_posting_posts',
739 ( is_array( $params ) ? $params : array() ),
740 (object) array(
741 'id' => $website->id,
742 'url' => $website->url,
743 'name' => $website->name,
744 )
745 );
746 }
747
748 $ch = curl_init();
749
750 $proxy = new \WP_HTTP_Proxy();
751 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
752 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
753 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
754 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
755
756 if ( $proxy->use_authentication() ) {
757 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
758 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
759 }
760 }
761
762 if ( ( null !== $website ) && ( ( property_exists( $website, 'wpe' ) && 1 !== $website->wpe ) || ( isset( $others['upgrade'] ) && ( true === $others['upgrade'] ) ) ) ) {
763 // to fix.
764 if ( defined( 'LOGGED_IN_SALT' ) && defined( 'NONCE_SALT' ) ) {
765 $cookie_salt = sha1( sha1( 'mainwp' . LOGGED_IN_SALT . $website->id ) . NONCE_SALT . 'WP_Cookie' );
766 } else {
767 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' );
768 }
769 $cookieFile = $cookieDir . '/' . $cookie_salt;
770 if ( ! file_exists( $cookieFile ) ) {
771 @file_put_contents( $cookieFile, '' );
772 }
773
774 if ( file_exists( $cookieFile ) ) {
775 @chmod( $cookieFile, 0644 );
776 curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookieFile );
777 curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookieFile );
778 }
779 }
780
781 curl_setopt( $ch, CURLOPT_URL, $url );
782 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
783 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
784 curl_setopt( $ch, CURLOPT_POST, true );
785
786 $postdata = self::get_post_data_authed( $website, $what, $params );
787 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
788 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
789 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
790 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
791 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
792 $http_pass = stripslashes( $http_pass );
793 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
794 }
795
796 $ssl_verifyhost = false;
797 $verifyCertificate = isset( $website->verify_certificate ) ? (int) $website->verify_certificate : null;
798 if ( null !== $verifyCertificate ) {
799 if ( 1 === $verifyCertificate ) {
800 $ssl_verifyhost = true;
801 } elseif ( 2 === $verifyCertificate ) {
802 if ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
803 $ssl_verifyhost = true;
804 }
805 }
806 } elseif ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
807 $ssl_verifyhost = true;
808 }
809
810 if ( $ssl_verifyhost ) {
811 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
812 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
813 } else {
814 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false );
815 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
816 }
817
818 curl_setopt( $ch, CURLOPT_SSLVERSION, $website->ssl_version );
819
820 if ( is_object( $website ) && property_exists( $website, 'id' ) ) {
821 $http_version = apply_filters( 'mainwp_curl_http_version', false, $website->id );
822 if ( false !== $http_version ) {
823 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
824 }
825
826 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, $website->id, $website->url );
827 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
828 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
829 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
830 }
831 }
832
833 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
834 MainWP_System_Utility::set_time_limit( $timeout );
835
836 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
837 @curl_multi_add_handle( $mh, $ch );
838 }
839
840 $handleToWebsite[ self::get_resource_id( $ch ) ] = $website;
841 $requestUrls[ self::get_resource_id( $ch ) ] = $website->url;
842 $requestHandles[ self::get_resource_id( $ch ) ] = $ch;
843
844 if ( null !== $_new_post ) {
845 $params['new_post'] = $_new_post;
846 }
847 }
848
849 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
850 $lastRun = 0;
851 do {
852 if ( 20 < time() - $lastRun ) {
853 MainWP_System_Utility::set_time_limit( $timeout );
854 $lastRun = time();
855 }
856
857 curl_multi_exec( $mh, $running );
858 while ( $info = curl_multi_info_read( $mh ) ) {
859 $data = curl_multi_getcontent( $info['handle'] );
860 $contains = ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) );
861 curl_multi_remove_handle( $mh, $info['handle'] );
862
863 if ( ! $contains && isset( $requestUrls[ self::get_resource_id( $info['handle'] ) ] ) ) {
864 curl_setopt( $info['handle'], CURLOPT_URL, $requestUrls[ self::get_resource_id( $info['handle'] ) ] );
865 curl_multi_add_handle( $mh, $info['handle'] );
866 unset( $requestUrls[ self::get_resource_id( $info['handle'] ) ] );
867 ++$running;
868 continue;
869 }
870
871 if ( null !== $handler ) {
872 $site = &$handleToWebsite[ self::get_resource_id( $info['handle'] ) ];
873 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
874 }
875
876 unset( $handleToWebsite[ self::get_resource_id( $info['handle'] ) ] );
877 if ( 'resource' === gettype( $info['handle'] ) ) {
878 curl_close( $info['handle'] );
879 }
880 unset( $info['handle'] );
881 }
882 usleep( 10000 );
883 } while ( $running > 0 );
884
885 if ( 'resource' === gettype( $mh ) ) {
886 curl_multi_close( $mh );
887 }
888 } else {
889 foreach ( $requestHandles as $id => $ch ) {
890 $data = curl_exec( $ch );
891
892 if ( null !== $handler ) {
893 $site = &$handleToWebsite[ self::get_resource_id( $ch ) ];
894 call_user_func_array( $handler, array( $data, $site, &$output, $params ) );
895 }
896 }
897 }
898
899 return true;
900 }
901
902 /**
903 * Credits WordPress org.
904 *
905 * Get the correct "Expect" header for the given request data.
906 *
907 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
908 * @return string The "Expect" header.
909 */
910 protected static function get_expect_header( $data ) {
911 if ( ! is_array( $data ) ) {
912 return strlen( (string) $data ) >= 1048576 ? '100-Continue' : '';
913 }
914
915 $bytesize = 0;
916 $iterator = new \RecursiveIteratorIterator( new \RecursiveArrayIterator( $data ) );
917
918 foreach ( $iterator as $datum ) {
919 $bytesize += strlen( (string) $datum );
920
921 if ( $bytesize >= 1048576 ) {
922 return '100-Continue';
923 }
924 }
925
926 return '';
927 }
928
929 /**
930 * Method get_resource_id()
931 *
932 * Get resource id.
933 *
934 * @param mixed $res The given resource.
935 *
936 * @return $result Resource ID only.
937 */
938 public static function get_resource_id( $res ) {
939 $result = false;
940 if ( is_a( $res, 'CurlHandle' ) ) {
941 $result = spl_object_hash( $res );
942 } elseif ( is_resource( $res ) ) {
943 $resourceString = (string) $res;
944 $exploded = explode( '#', $resourceString );
945 $result = array_pop( $exploded );
946 }
947 return $result;
948 }
949
950 /**
951 * Method get_lock_identifier().
952 *
953 * Get lock identifier.
954 *
955 * @param mixed $pLockName Provided Lock Name.
956 *
957 * @return mixed false|sem_get()|@fopen
958 */
959 public static function get_lock_identifier( $pLockName ) {
960 if ( ( null === $pLockName ) || ( false === $pLockName ) ) {
961 return false;
962 }
963
964 if ( function_exists( 'sem_get' ) ) {
965 return sem_get( $pLockName );
966 } else {
967 $fh = @fopen( sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'lock' . $pLockName . '.txt', 'w+' );
968 if ( ! $fh ) {
969 return false;
970 }
971
972 return $fh;
973 }
974
975 return false;
976 }
977
978 /**
979 * Method lock()
980 *
981 * Use sem_acquire or @flock to lock the $identifier.
982 *
983 * @param mixed $identifier Identifier.
984 *
985 * @return mixed false|sem_acquire()|@flock
986 */
987 public static function lock( $identifier ) {
988 if ( ( null === $identifier ) || ( false === $identifier ) ) {
989 return false;
990 }
991
992 if ( function_exists( 'sem_acquire' ) ) {
993 return sem_acquire( $identifier );
994 } else {
995 if ( ! is_resource( $identifier ) ) {
996 return false; // to fix.
997 }
998 for ( $i = 0; $i < 3; $i++ ) {
999 if ( @flock( $identifier, LOCK_EX ) ) {
1000 return $identifier;
1001 } else {
1002 sleep( 1 );
1003 }
1004 }
1005
1006 return false;
1007 }
1008
1009 return false;
1010 }
1011
1012 /**
1013 * Method release()
1014 *
1015 * Use sem_release or @flock, @fclose to unlock $identifier.
1016 *
1017 * @param mixed $identifier Identifier.
1018 *
1019 * @return mixed false|sem_release()|@flock
1020 */
1021 public static function release( $identifier ) {
1022 if ( ( null === $identifier ) || ( false === $identifier ) ) {
1023 return false;
1024 }
1025
1026 if ( function_exists( 'sem_release' ) ) {
1027 return sem_release( $identifier );
1028 } else {
1029 if ( ! is_resource( $identifier ) ) {
1030 return false; // to fix.
1031 }
1032 @flock( $identifier, LOCK_UN );
1033 @fclose( $identifier );
1034 }
1035
1036 return false;
1037 }
1038
1039 /**
1040 * Method fetch_url_authed()
1041 *
1042 * Updates the child site via authenticated request.
1043 *
1044 * @param object $website Website information.
1045 * @param string $what Function to perform.
1046 * @param null $params Function parameters.
1047 * @param bool $checkConstraints Whether or not to check constraints.
1048 * @param bool $pForceFetch Whether or not to force the fetch.
1049 * @param bool $pRetryFailed Whether or not to retry the fetch process.
1050 * @param null $rawResponse Raw response.
1051 *
1052 * @return mixed $information
1053 *
1054 * @uses \MainWP\Dashboard\MainWP_Monitoring_Handler::handle_check_website()
1055 * @uses \MainWP\Dashboard\MainWP_Premium_Update::maybe_request_premium_updates()
1056 * @uses \MainWP\Dashboard\MainWP_Sync::sync_information_array()
1057 */
1058 public static function fetch_url_authed(
1059 &$website,
1060 $what,
1061 $params = null,
1062 $checkConstraints = false,
1063 $pForceFetch = false,
1064 $pRetryFailed = true,
1065 $rawResponse = null
1066 ) {
1067
1068 // to support demo data.
1069 if ( MainWP_Demo_Handle::get_instance()->is_demo_website( $website ) ) {
1070 return MainWP_Demo_Handle::get_instance()->handle_action_demo( $website, $what );
1071 }
1072
1073 if ( ! is_array( $params ) ) {
1074 $params = array();
1075 }
1076
1077 $others = array(
1078 'force_use_ipv4' => $website->force_use_ipv4,
1079 'upgrade' => ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ),
1080 );
1081
1082 $request_update = MainWP_Premium_Update::maybe_request_premium_updates( $website, $what, $params );
1083
1084 if ( isset( $rawResponse ) && $rawResponse ) {
1085 $others['raw_response'] = 'yes';
1086 }
1087
1088 $params['optimize'] = ( ( 1 === (int) get_option( 'mainwp_optimize', 1 ) ) ? 1 : 0 );
1089
1090 $updating_website = false;
1091 $type = '';
1092 $list = '';
1093 if ( 'upgradeplugintheme' === $what || 'upgrade' === $what || 'upgradetranslation' === $what ) {
1094 $updating_website = true;
1095 if ( 'upgradeplugintheme' === $what || 'upgradetranslation' === $what ) {
1096 $type = $params['type'];
1097 $list = $params['list'];
1098 } else {
1099 $type = 'wp';
1100 $list = '';
1101 }
1102 }
1103
1104 if ( $updating_website ) {
1105 /**
1106 * Action: mainwp_website_before_updated
1107 *
1108 * Fires before the child site update process.
1109 *
1110 * @param object $website Object containing child site info.
1111 * @param string $type Type parameter.
1112 * @param string $list List parameter.
1113 *
1114 * @since Unknown
1115 */
1116 do_action( 'mainwp_website_before_updated', $website, $type, $list );
1117 }
1118
1119 if ( 'renew' === $what ) {
1120 $postdata = self::get_renew_post_data_authed( $website, $what );
1121 } else {
1122 $postdata = self::get_post_data_authed( $website, $what, $params );
1123
1124 }
1125 $others['function'] = $what;
1126
1127 $information = array();
1128
1129 if ( ! $request_update ) {
1130 $information = self::fetch_url( $website, $website->url, $postdata, $checkConstraints, $website->verify_certificate, $pRetryFailed, $website->http_user, $website->http_pass, $website->ssl_version, $others );
1131 /**
1132 * Fires immediately after fetch url action.
1133 *
1134 * @param object $website website.
1135 * @param array $information information result data.
1136 * @param string $what action.
1137 * @param array $params params input array.
1138 * @param array $others others input array.
1139 *
1140 * @since 4.5.1.1
1141 */
1142 do_action( 'mainwp_fetch_url_authed', $website, $information, $what, $params, $others );
1143 } else {
1144 $slug = $params['list'];
1145 $information['upgrades'] = array( $slug => 1 );
1146 }
1147
1148 if ( is_array( $information ) && isset( $information['sync'] ) && ! empty( $information['sync'] ) ) {
1149 MainWP_Sync::sync_information_array( $website, $information['sync'] );
1150 unset( $information['sync'] );
1151 }
1152
1153 if ( $updating_website ) {
1154 /**
1155 * Action: mainwp_website_updated
1156 *
1157 * Fires after the child site update process.
1158 *
1159 * @param object $website Object containing child site info.
1160 * @param string $type Type parameter.
1161 * @param string $list List parameter.
1162 * @param array $information Array containing the information fetched from the child site.
1163 *
1164 * @since Unknown
1165 */
1166 do_action( 'mainwp_website_updated', $website, $type, $list, $information );
1167 if ( 1 === (int) get_option( 'mainwp_check_http_response', 0 ) ) {
1168 MainWP_Monitoring_Handler::handle_check_website( $website );
1169 }
1170 }
1171
1172 return $information;
1173 }
1174
1175 /**
1176 * Method fetch_url_not_authed()
1177 *
1178 * Fetch not authorized URL.
1179 *
1180 * @param string $url URL to fetch from.
1181 * @param string $admin Admin name.
1182 * @param string $what Function to perform.
1183 * @param null $params Function parameters.
1184 * @param bool $pForceFetch true|false Whether or not to force the fetch.
1185 * @param null $verifyCertificate Verify the SSL Certificate.
1186 * @param null $http_user htaccess username.
1187 * @param null $http_pass htaccess password.
1188 * @param integer $sslVersion SSL version to check for.
1189 * @param array $others Other functions to perform.
1190 * @param array $output Output values.
1191 *
1192 * @return mixed self::fetch_url() Fetch URL.
1193 */
1194 public static function fetch_url_not_authed(
1195 $url,
1196 $admin,
1197 $what,
1198 $params = null,
1199 $pForceFetch = false,
1200 $verifyCertificate = null,
1201 $http_user = null,
1202 $http_pass = null,
1203 $sslVersion = 0,
1204 $others = array(),
1205 &$output = array()
1206 ) {
1207
1208 if ( empty( $params ) ) {
1209 $params = array();
1210 }
1211
1212 $postdata = self::get_post_data_not_authed( $url, $admin, $what, $params );
1213 $website = null;
1214
1215 $others['function'] = $what;
1216 return self::fetch_url( $website, $url, $postdata, false, $verifyCertificate, true, $http_user, $http_pass, $sslVersion, $others, $output );
1217 }
1218
1219 /**
1220 * Method fetch_url()
1221 *
1222 * Fetch URL.
1223 *
1224 * @param object $website Child Site info.
1225 * @param string $url URL to fetch from.
1226 * @param mixed $postdata Post data to fetch.
1227 * @param bool $checkConstraints true|false Whether or not to check constraints.
1228 * @param null $verifyCertificate Verify SSL Certificate.
1229 * @param bool $pRetryFailed ture|false Whether or not the Retry has failed.
1230 * @param null $http_user htaccess username.
1231 * @param null $http_pass htaccess password.
1232 * @param integer $sslVersion SSL version.
1233 * @param array $others Other functions to perform.
1234 * @param array $output Output values.
1235 *
1236 * @throws \Exception Exception message.
1237 *
1238 * @return mixed self::fetch_url_site()
1239 */
1240 public static function fetch_url(
1241 &$website,
1242 $url,
1243 $postdata,
1244 $checkConstraints = false,
1245 $verifyCertificate = null,
1246 $pRetryFailed = true,
1247 $http_user = null,
1248 $http_pass = null,
1249 $sslVersion = 0,
1250 $others = array(),
1251 &$output = array()
1252 ) {
1253
1254 $start = time();
1255
1256 try {
1257 $tmpUrl = $url;
1258 if ( '/' !== substr( $tmpUrl, - 1 ) ) {
1259 $tmpUrl .= '/';
1260 }
1261
1262 if ( false === strpos( $url, 'wp-admin' ) ) {
1263 $tmpUrl .= 'wp-admin/admin-ajax.php';
1264 }
1265
1266 return self::fetch_url_site( $website, $tmpUrl, $postdata, $checkConstraints, $verifyCertificate, $http_user, $http_pass, $sslVersion, $others, $output );
1267 } catch ( \Exception $e ) {
1268 if ( ! $pRetryFailed || ( 30 < ( time() - $start ) ) ) {
1269 throw $e;
1270 }
1271
1272 try {
1273 return self::fetch_url_site( $website, $url, $postdata, $checkConstraints, $verifyCertificate, $http_user, $http_pass, $sslVersion, $others, $output );
1274 } catch ( \Exception $ex ) {
1275 throw $e;
1276 }
1277 }
1278 }
1279
1280 /**
1281 * Method fetch_url_site()
1282 *
1283 * M Fetch URL.
1284 *
1285 * @param object $website Child Site info.
1286 * @param string $url URL to fetch from.
1287 * @param mixed $postdata Post data to fetch.
1288 * @param bool $checkConstraints true|false Whether or not to check constraints.
1289 * @param null $verifyCertificate Verify SSL Certificate.
1290 * @param null $http_user htaccess username.
1291 * @param null $http_pass htaccess password.
1292 * @param integer $sslVersion SSL version.
1293 * @param array $others Other functions to perform.
1294 * @param array $output Output values.
1295 *
1296 * @return mixed $data, $information.
1297 * @throws MainWP_Exception Exception message.
1298 *
1299 * @uses \MainWP\Dashboard\MainWP_DB_Common::insert_or_update_request_log()
1300 * @uses \MainWP\Dashboard\MainWP_Exception
1301 * @uses \MainWP\Dashboard\MainWP_Logger::debug_for_website()
1302 * @uses \MainWP\Dashboard\MainWP_System::$version
1303 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_mainwp_dir()
1304 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_child_response()
1305 * @uses \MainWP\Dashboard\MainWP_Utility::value_to_string()
1306 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
1307 */
1308 public static function fetch_url_site( // phpcs:ignore -- complex method. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
1309 &$website,
1310 $url,
1311 $postdata,
1312 $checkConstraints = false,
1313 $verifyCertificate = null,
1314 $http_user = null,
1315 $http_pass = null,
1316 $sslVersion = 0,
1317 $others = array(),
1318 &$output = array()
1319 ) {
1320
1321 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1322
1323 if ( ! empty( $website ) ) {
1324 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Request to [' . $url . '] [' . MainWP_Utility::value_to_string( $postdata, 1 ) . ']' );
1325 }
1326
1327 $identifier = null;
1328 if ( $checkConstraints ) {
1329 self::check_constraints( $identifier, $website );
1330 }
1331
1332 if ( null !== $website ) {
1333 MainWP_DB_Common::instance()->insert_or_update_request_log( $website->id, null, microtime( true ), null );
1334 }
1335
1336 if ( null !== $identifier ) {
1337 self::release( $identifier );
1338 }
1339
1340 $dirs = MainWP_System_Utility::get_mainwp_dir();
1341 $cookieDir = $dirs[0] . 'cookies';
1342
1343 self::init_cookiesdir( $cookieDir );
1344
1345 $ch = curl_init();
1346
1347 $proxy = new \WP_HTTP_Proxy();
1348 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1349 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1350 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1351 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1352
1353 if ( $proxy->use_authentication() ) {
1354 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1355 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1356 }
1357 }
1358
1359 if ( ( null !== $website ) && ( ( property_exists( $website, 'wpe' ) && 1 !== $website->wpe ) || ( isset( $others['upgrade'] ) && ( true === $others['upgrade'] ) ) ) ) {
1360 // to fix.
1361 if ( defined( 'LOGGED_IN_SALT' ) && defined( 'NONCE_SALT' ) ) {
1362 $cookie_salt = sha1( sha1( 'mainwp' . LOGGED_IN_SALT . $website->id ) . NONCE_SALT . 'WP_Cookie' );
1363 } else {
1364 $cookie_salt = sha1( sha1( 'mainwp' . $website->id ) . 'WP_Cookie' );
1365 }
1366 $cookieFile = $cookieDir . '/' . $cookie_salt;
1367 if ( ! file_exists( $cookieFile ) ) {
1368 @file_put_contents( $cookieFile, '' );
1369 }
1370
1371 if ( file_exists( $cookieFile ) ) {
1372 @chmod( $cookieFile, 0644 );
1373 curl_setopt( $ch, CURLOPT_COOKIEJAR, $cookieFile );
1374 curl_setopt( $ch, CURLOPT_COOKIEFILE, $cookieFile );
1375 }
1376 }
1377
1378 curl_setopt( $ch, CURLOPT_URL, $url );
1379 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
1380 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
1381 curl_setopt( $ch, CURLOPT_POST, true );
1382 curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
1383 curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
1384 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1385 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1386
1387 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
1388 $http_pass = stripslashes( $http_pass );
1389 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
1390 }
1391
1392 $ssl_verifyhost = false;
1393 if ( null !== $verifyCertificate ) {
1394 if ( 1 === (int) $verifyCertificate ) {
1395 $ssl_verifyhost = true;
1396 } elseif ( 2 === (int) $verifyCertificate ) {
1397 if ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
1398 $ssl_verifyhost = true;
1399 }
1400 }
1401 } elseif ( ( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || ( 1 === (int) get_option( 'mainwp_sslVerifyCertificate' ) ) ) ) {
1402 $ssl_verifyhost = true;
1403 }
1404
1405 if ( $ssl_verifyhost ) {
1406 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
1407 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
1408 } else {
1409 curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false );
1410 curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
1411 }
1412
1413 curl_setopt( $ch, CURLOPT_SSLVERSION, $sslVersion );
1414
1415 if ( is_object( $website ) && property_exists( $website, 'id' ) ) {
1416 $http_version = apply_filters( 'mainwp_curl_http_version', false, $website->id );
1417 if ( false !== $http_version ) {
1418 curl_setopt( $ch, CURLOPT_HTTP_VERSION, $http_version );
1419 }
1420 $curlopt_resolve = apply_filters( 'mainwp_curl_curlopt_resolve', false, $website->id, $website->url );
1421 if ( is_array( $curlopt_resolve ) && ! empty( $curlopt_resolve ) ) {
1422 curl_setopt( $ch, CURLOPT_RESOLVE, $curlopt_resolve );
1423 curl_setopt( $ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false );
1424 }
1425 }
1426
1427 $headers = array( 'X-Requested-With' => 'XMLHttpRequest' );
1428 $headers['Expect'] = self::get_expect_header( $postdata );
1429
1430 if ( class_exists( '\WpOrg\Requests\Requests' ) ) {
1431 $headers = \WpOrg\Requests\Requests::flatten( $headers );
1432 } else {
1433 $headers = \Requests::flatten( $headers );
1434 }
1435
1436 curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
1437 curl_setopt( $ch, CURLOPT_REFERER, get_option( 'siteurl' ) );
1438
1439 $force_use_ipv4 = false;
1440 $forceUseIPv4 = isset( $others['force_use_ipv4'] ) ? (int) $others['force_use_ipv4'] : null;
1441 if ( null !== $forceUseIPv4 ) {
1442 if ( 1 === $forceUseIPv4 ) {
1443 $force_use_ipv4 = true;
1444 } elseif ( 2 === $forceUseIPv4 ) {
1445 if ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
1446 $force_use_ipv4 = true;
1447 }
1448 }
1449 } elseif ( 1 === (int) get_option( 'mainwp_forceUseIPv4' ) ) {
1450 $force_use_ipv4 = true;
1451 }
1452
1453 if ( $force_use_ipv4 ) {
1454 if ( defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
1455 curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
1456 }
1457 }
1458
1459 $timeout = 20 * 60 * 60;
1460 curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout );
1461 MainWP_System_Utility::set_time_limit( $timeout );
1462
1463 MainWP_Utility::end_session();
1464
1465 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Executing handlers' );
1466
1467 $disabled_functions = ini_get( 'disable_functions' );
1468 if ( empty( $disabled_functions ) || ( false === stristr( $disabled_functions, 'curl_multi_exec' ) ) ) {
1469 $mh = @curl_multi_init();
1470 @curl_multi_add_handle( $mh, $ch );
1471
1472 $lastRun = 0;
1473 do {
1474 if ( 20 < time() - $lastRun ) {
1475 MainWP_System_Utility::set_time_limit( $timeout );
1476 $lastRun = time();
1477 }
1478 @curl_multi_exec( $mh, $running );
1479 while ( $info = @curl_multi_info_read( $mh ) ) {
1480 $data = @curl_multi_getcontent( $info['handle'] );
1481
1482 $http_status = @curl_getinfo( $info['handle'], CURLINFO_HTTP_CODE );
1483 $err = @curl_error( $info['handle'] );
1484 $real_url = @curl_getinfo( $info['handle'], CURLINFO_EFFECTIVE_URL );
1485
1486 @curl_multi_remove_handle( $mh, $info['handle'] );
1487 }
1488 usleep( 10000 );
1489 } while ( $running > 0 );
1490 if ( 'resource' === gettype( $mh ) ) {
1491 @curl_multi_close( $mh );
1492 }
1493 } else {
1494 $data = @curl_exec( $ch );
1495 $http_status = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1496 $err = @curl_error( $ch );
1497 $real_url = @curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
1498 }
1499
1500 $host = wp_parse_url( $real_url, PHP_URL_HOST );
1501 $ip = gethostbyname( $host );
1502
1503 if ( null !== $website ) {
1504 MainWP_DB_Common::instance()->insert_or_update_request_log( $website->id, $ip, null, microtime( true ) );
1505 }
1506
1507 $raw_response = isset( $others['raw_response'] ) && 'yes' === $others['raw_response'] ? true : false;
1508
1509 $output['fetch_data'] = $data;
1510 $output['http_status'] = (int) $http_status;
1511
1512 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'http status: [' . $http_status . '] err: [' . $err . ']' );
1513 if ( '400' === $http_status ) {
1514 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'post data: [' . MainWP_Utility::value_to_string( $postdata, 1 ) . ']' );
1515 }
1516
1517 MainWP_Logger::instance()->log_execution_time( 'fetch_url_site :: [url=' . $url . ']' );
1518
1519 $thr_error = null;
1520
1521 if ( ( false === $data ) && empty( $http_status ) ) {
1522 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=0][' . $err . ']' );
1523 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1524 } elseif ( empty( $data ) && ! empty( $err ) ) {
1525 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] HTTP Error: [status=' . $http_status . '][' . $err . ']' );
1526 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1527 } elseif ( 0 < preg_match( '/<mainwp>(.*)<\/mainwp>/', $data, $results ) ) {
1528 $result = $results[1];
1529 $information = MainWP_System_Utility::get_child_response( base64_decode( $result ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode used for http encoding compatible.
1530 unset( $output['fetch_data'] ); // hide the data.
1531 $data_log = is_array( $postdata ) ? print_r( $postdata, true ) : ( is_string( $postdata ) ? $postdata : '' ); //phpcs:ignore -- good.
1532 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', '[' . $url . '] postdata [' . $data_log . '] information: [OK]' ); //phpcs:ignore -- ok.
1533 return $information;
1534 } elseif ( 200 === (int) $http_status && ! empty( $err ) ) {
1535 $thr_error = new MainWP_Exception( 'HTTPERROR', $err ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1536 } elseif ( $raw_response ) {
1537 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url_site', 'Response: [RAW]' );
1538 return $data;
1539 } else {
1540 MainWP_Logger::instance()->debug_for_website( $website, 'fetch_url', '[' . $url . '] Error: NOMAINWP' );
1541 $detect_wsidchk = is_string( $data ) ? strpos( $data, 'wsidchk' ) : false;
1542 if ( false !== $detect_wsidchk ) {
1543 $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 );
1544 } else {
1545 $thr_error = new MainWP_Exception( 'NOMAINWP', $url ); //phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
1546 }
1547 }
1548
1549 if ( null !== $thr_error ) {
1550 $thr_error->set_data( $data );
1551 throw $thr_error;
1552 }
1553 }
1554
1555 /**
1556 * Method check_constraints()
1557 *
1558 * Check connection delay constraints.
1559 *
1560 * @param mixed $identifier Lock identifier.
1561 * @param mixed $website Object child site.
1562 *
1563 * @uses \MainWP\Dashboard\MainWP_DB_Common::close_open_requests()
1564 * @uses \MainWP\Dashboard\MainWP_DB::get_wp_ip()
1565 * @uses \MainWP\Dashboard\MainWP_Utility::end_session()
1566 */
1567 private static function check_constraints( &$identifier, $website ) { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
1568 $semLock = '103218';
1569 $identifier = self::get_lock_identifier( $semLock );
1570 $minimumDelay = ( ( false === get_option( 'mainwp_minimumDelay' ) ) ? 200 : get_option( 'mainwp_minimumDelay' ) );
1571 if ( 0 < $minimumDelay ) {
1572 $minimumDelay = $minimumDelay / 1000;
1573 }
1574 $minimumIPDelay = ( ( false === get_option( 'mainwp_minimumIPDelay' ) ) ? 1000 : get_option( 'mainwp_minimumIPDelay' ) );
1575 if ( 0 < $minimumIPDelay ) {
1576 $minimumIPDelay = $minimumIPDelay / 1000;
1577 }
1578
1579 MainWP_Utility::end_session();
1580 $delay = true;
1581 while ( $delay ) {
1582 self::lock( $identifier );
1583 if ( 0 < $minimumDelay && self::check_constraints_last_request( $identifier, $minimumDelay ) ) {
1584 continue;
1585 }
1586
1587 if ( 0 < $minimumIPDelay && null !== $website ) {
1588 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1589 if ( null !== $ip && '' !== $ip ) {
1590 if ( self::check_constraints_last_request( $identifier, $minimumIPDelay, $ip ) ) {
1591 continue;
1592 }
1593 }
1594 }
1595 $delay = false;
1596 }
1597
1598 $maximumRequests = ( ( false === get_option( 'mainwp_maximumRequests' ) ) ? 4 : get_option( 'mainwp_maximumRequests' ) );
1599 $maximumIPRequests = ( ( false === get_option( 'mainwp_maximumIPRequests' ) ) ? 1 : get_option( 'mainwp_maximumIPRequests' ) );
1600
1601 $first = true;
1602 $delay = true;
1603 while ( $delay ) {
1604 if ( ! $first ) {
1605 self::lock( $identifier );
1606 } else {
1607 $first = false;
1608 }
1609
1610 MainWP_DB_Common::instance()->close_open_requests();
1611
1612 if ( 0 < $maximumRequests && self::check_constraints_open_requests( $identifier, $maximumRequests ) ) {
1613 continue;
1614 }
1615
1616 if ( 0 < $maximumIPRequests && null !== $website ) {
1617 $ip = MainWP_DB::instance()->get_wp_ip( $website->id );
1618 if ( null !== $ip && '' !== $ip ) {
1619 if ( self::check_constraints_open_requests( $identifier, $maximumIPRequests, $ip ) ) {
1620 continue;
1621 }
1622 }
1623 }
1624 $delay = false;
1625 }
1626 }
1627
1628 /**
1629 * Method check_constraints_last_request().
1630 *
1631 * Check constraints for last requests.
1632 *
1633 * @param mixed $identifier connect identifier.
1634 * @param int $minimumDelay minimum delay.
1635 * @param string|null $ip ip address.
1636 *
1637 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_last_request_timestamp()
1638 */
1639 private static function check_constraints_last_request( $identifier, $minimumDelay, $ip = null ) {
1640 $lastRequest = MainWP_DB_Common::instance()->get_last_request_timestamp( $ip );
1641 if ( $lastRequest > ( ( microtime( true ) ) - $minimumDelay ) ) {
1642 self::release( $identifier );
1643 $sleep = ( $minimumDelay - ( ( microtime( true ) ) - $lastRequest ) ) * 1000 * 1000;
1644 $sleep = intval( $sleep );
1645 usleep( $sleep );
1646 return true;
1647 }
1648 return false;
1649 }
1650
1651 /**
1652 * Method check_constraints_open_requests().
1653 *
1654 * Check constraints for open requests.
1655 *
1656 * @param mixed $identifier connect identifier.
1657 * @param int $maximumRequests maximum requests.
1658 * @param string|null $ip ip address.
1659 *
1660 * @uses \MainWP\Dashboard\MainWP_DB_Common::get_nrof_open_requests()
1661 */
1662 private static function check_constraints_open_requests( $identifier, $maximumRequests, $ip = null ) {
1663 $nrOfOpenRequests = MainWP_DB_Common::instance()->get_nrof_open_requests( $ip );
1664 if ( $nrOfOpenRequests >= $maximumRequests ) {
1665 self::release( $identifier );
1666 usleep( 200000 );
1667 return true;
1668 }
1669 return false;
1670 }
1671
1672 /**
1673 * Method download_to_file()
1674 *
1675 * Download to file.
1676 *
1677 * @param mixed $url Download URL.
1678 * @param mixed $file File to download to.
1679 * @param bool $size Size of file.
1680 * @param null $http_user htaccess username.
1681 * @param null $http_pass htaccess password.
1682 *
1683 * @throws MainWP_Exception Exception message.
1684 *
1685 * @uses \MainWP\Dashboard\MainWP_Exception
1686 * @uses \MainWP\Dashboard\MainWP_System::$version
1687 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1688 */
1689 public static function download_to_file( $url, $file, $size = false, $http_user = null, $http_pass = null ) {
1690
1691 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1692
1693 /**
1694 * WordPress files system object.
1695 *
1696 * @global object
1697 */
1698 global $wp_filesystem;
1699
1700 if ( $wp_filesystem->exists( $file ) && ( ( false === $size ) || ( $wp_filesystem->size( $file ) > $size ) ) ) {
1701 $wp_filesystem->delete( $file );
1702 }
1703
1704 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1705 $wp_filesystem->mkdir( dirname( $file ), 0777 );
1706 }
1707
1708 if ( ! $wp_filesystem->exists( dirname( $file ) ) ) {
1709 throw new MainWP_Exception( esc_html__( 'MainWP plugin could not create directory in order to download the file.', 'mainwp' ) );
1710 }
1711
1712 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1713 if ( ! $wp_filesystem->is_writable( @dirname( $file ) ) ) {
1714 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1715 }
1716 } elseif ( ! is_writable( @dirname( $file ) ) ) { //phpcs:ignore -- ok.
1717 throw new MainWP_Exception( esc_html__( 'MainWP upload directory is not writable.', 'mainwp' ) );
1718 }
1719
1720 $fp = fopen( $file, 'a' );
1721 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1722 if ( false !== $size ) {
1723 if ( $wp_filesystem->exists( $file ) ) {
1724 $size = $wp_filesystem->size( $file );
1725 $url .= '&foffset=' . $size;
1726 }
1727 }
1728 $ch = curl_init( str_replace( ' ', '%20', $url ) );
1729
1730 $proxy = new \WP_HTTP_Proxy();
1731 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1732 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1733 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1734 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1735
1736 if ( $proxy->use_authentication() ) {
1737 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1738 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1739 }
1740 }
1741
1742 curl_setopt( $ch, CURLOPT_FILE, $fp );
1743 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1744 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1745 curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
1746 if ( ! empty( $http_user ) && ! empty( $http_pass ) ) {
1747 $http_pass = stripslashes( $http_pass );
1748 curl_setopt( $ch, CURLOPT_USERPWD, "$http_user:$http_pass" );
1749 }
1750 curl_exec( $ch );
1751 if ( 'resource' === gettype( $ch ) ) {
1752 curl_close( $ch );
1753 }
1754 fclose( $fp );
1755 }
1756
1757 /**
1758 * Method init_coockiesdir()
1759 *
1760 * Check for cookies directory and create it if it doesn't already exist,
1761 * set the file permissions and update htaccess.
1762 *
1763 * @param mixed $cookieDir Cookies directory.
1764 *
1765 * @return void
1766 *
1767 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_wp_file_system()
1768 */
1769 public static function init_cookiesdir( $cookieDir ) {
1770
1771 $hasWPFileSystem = MainWP_System_Utility::get_wp_file_system();
1772
1773 /**
1774 * WordPress files system object.
1775 *
1776 * @global object
1777 */
1778 global $wp_filesystem;
1779
1780 if ( $hasWPFileSystem && ! empty( $wp_filesystem ) ) {
1781
1782 if ( ! $wp_filesystem->is_dir( $cookieDir ) ) {
1783 $wp_filesystem->mkdir( $cookieDir, 0777 );
1784 }
1785
1786 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1787 $file_htaccess = $cookieDir . '/.htaccess';
1788 $wp_filesystem->put_contents( $file_htaccess, 'deny from all' );
1789 }
1790
1791 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1792 $file_index = $cookieDir . '/index.php';
1793 $wp_filesystem->touch( $file_index );
1794 }
1795 } else {
1796
1797 if ( ! file_exists( $cookieDir ) ) {
1798 @mkdir( $cookieDir, 0777, true );
1799 }
1800
1801 if ( ! file_exists( $cookieDir . '/.htaccess' ) ) {
1802 $file_htaccess = @fopen( $cookieDir . '/.htaccess', 'w+' );
1803 @fwrite( $file_htaccess, 'deny from all' );
1804 @fclose( $file_htaccess );
1805 }
1806
1807 if ( ! file_exists( $cookieDir . '/index.php' ) ) {
1808 $file_index = @fopen( $cookieDir . '/index.php', 'w+' );
1809 @fclose( $file_index );
1810 }
1811 }
1812 }
1813
1814 /**
1815 * Method get_file_content()
1816 *
1817 * Get contents of file.
1818 *
1819 * @param mixed $url File Location.
1820 *
1821 * @return mixed false|$data
1822 *
1823 * @uses \MainWP\Dashboard\MainWP_System::$version
1824 */
1825 public static function get_file_content( $url ) {
1826 $agent = 'Mozilla/5.0 (compatible; MainWP/' . MainWP_System::$version . '; +http://mainwp.com)';
1827 $ch = curl_init();
1828
1829 $proxy = new \WP_HTTP_Proxy();
1830 if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
1831 curl_setopt( $ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
1832 curl_setopt( $ch, CURLOPT_PROXY, $proxy->host() );
1833 curl_setopt( $ch, CURLOPT_PROXYPORT, $proxy->port() );
1834
1835 if ( $proxy->use_authentication() ) {
1836 curl_setopt( $ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
1837 curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
1838 }
1839 }
1840
1841 curl_setopt( $ch, CURLOPT_HEADER, 0 );
1842 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1843 curl_setopt( $ch, CURLOPT_URL, $url );
1844 curl_setopt( $ch, CURLOPT_USERAGENT, $agent );
1845 curl_setopt( $ch, CURLOPT_ENCODING, 'none' );
1846
1847 $data = @curl_exec( $ch );
1848 $httpCode = @curl_getinfo( $ch, CURLINFO_HTTP_CODE );
1849 if ( 'resource' === gettype( $ch ) ) {
1850 curl_close( $ch );
1851 }
1852 if ( 200 === (int) $httpCode ) {
1853 return $data;
1854 } else {
1855 return false;
1856 }
1857 }
1858
1859 /**
1860 * Method get_favico_url()
1861 *
1862 * Get Child Site favicon URL.
1863 *
1864 * @param mixed $website Child Site info.
1865 *
1866 * @return mixed $faviurl Favicon URL.
1867 *
1868 * @uses \MainWP\Dashboard\MainWP_DB::get_website_option()
1869 * @uses \MainWP\Dashboard\MainWP_System_Utility::get_icons_dir()
1870 * @uses \MainWP\Dashboard\MainWP_Utility::remove_http_prefix()
1871 */
1872 public static function get_favico_url( $website ) {
1873 $favi = MainWP_DB::instance()->get_website_option( $website, 'favi_icon', '' );
1874 $faviurl = '';
1875
1876 if ( ! empty( $favi ) ) {
1877 if ( false !== strpos( $favi, 'favi-' . intval( $website->id ) . '-' ) ) {
1878 $dirs = MainWP_System_Utility::get_icons_dir();
1879 if ( file_exists( $dirs[0] . $favi ) ) {
1880 $faviurl = $dirs[1] . $favi;
1881 } else {
1882 $faviurl = '';
1883 }
1884 } elseif ( ( 0 === strpos( $favi, '//' ) ) || ( 0 === strpos( $favi, 'http' ) ) ) {
1885 $faviurl = $favi;
1886 } else {
1887 $faviurl = $website->url . $favi;
1888 $faviurl = MainWP_Utility::remove_http_prefix( $faviurl );
1889 }
1890 }
1891
1892 if ( empty( $faviurl ) ) {
1893 $faviurl = false;
1894 }
1895
1896 return $faviurl;
1897 }
1898 }
1899