tag check.', $stage ); } if ( isset( $is_errored ) ) { if ( method_exists( 'WP_Upgrader', 'release_lock' ) ) { \WP_Upgrader::release_lock( 'core_updater' ); } \WP_CLI::error( $is_errored ); return new \WP_Error( 'upgrade_verify_fail', $is_errored ); } return $retval; } /** * Fires at the end of the upgrade process * * @param object $upgrader Upgrader instance. * @param array $result Result of the upgrade process. */ public static function action_upgrader_process_complete( $upgrader, $result ) { // Check if the flag '--skip-packages' is used and honor it. $skip_check = false; if ( isset( $GLOBALS['argv'] ) ) { $args = $GLOBALS['argv']; if ( false !== array_search( '--skip-packages', $args ) ) { $skip_check = true; } } // If Skip Check is true, we hard-code in the site response // Else we do the checks. if ( $skip_check ) { $site_response = array( 'status_code' => 200, 'closing_body' => true, 'php_fatal' => false, ); } else { self::log_message( 'Fetching post-update site response...' ); $site_response = self::check_site_response( home_url( '/?nocache' ) ); $stage = 'post'; $http_code = $site_response['status_code']; if ( ! in_array( $http_code, self::valid_http_codes() ) ) { $is_errored = sprintf( 'Failed %s-update status code check (HTTP code %d).', $stage, $site_response['status_code'] ); } elseif ( ! empty( $site_response['php_fatal'] ) ) { $is_errored = sprintf( 'Failed %s-update PHP fatal error check.', $stage ); } elseif ( empty( $site_response['closing_body'] ) ) { $is_errored = sprintf( 'Failed %s-update closing tag check.', $stage ); } if ( isset( $is_errored ) ) { if ( method_exists( 'WP_Upgrader', 'release_lock' ) ) { \WP_Upgrader::release_lock( 'core_updater' ); } \WP_CLI::error( $is_errored ); return new \WP_Error( 'upgrade_verify_fail', $is_errored ); } } /** * Permit action based on the post-update site response check. * * @param array $site_response Values for the site heuristics check. * @param WP_Upgrader $upgrader The WP_Upgrader instance. */ do_action( 'upgrade_verify_upgrader_process_complete', $site_response, $upgrader ); } /** * Log a message to STDOUT * * @param string $message Message to render. */ private static function log_message( $message ) { if ( class_exists( 'WP_CLI' ) ) { \WP_CLI::log( $message ); } else { echo htmlentities( $message ) . PHP_EOL; } } /** * Check a site response for basic operating details and log output. * * @param string $url URL to check. * @return array Response data. */ public static function check_site_response( $url ) { $curl_response = self::url_test( $url ); if ( false === $curl_response ) { $response = array( 'status_code' => 418, 'body' => 'I\'m a little teapot (DreamHost).', ); } else { $response = self::get_site_response( $url ); } self::log_message( ' -> HTTP status code: ' . $response['status_code'] ); $site_response = array( 'status_code' => $response['status_code'], 'closing_body' => true, 'php_fatal' => false, ); if ( 418 !== $response['status_code'] ) { if ( false === stripos( $response['body'], '' ) ) { self::log_message( ' -> No closing tag detected.' ); $site_response['closing_body'] = false; } else { self::log_message( ' -> Correctly detected closing tag.' ); $site_response['closing_body'] = true; } $stripped_body = strip_tags( $response['body'] ); if ( false !== stripos( $stripped_body, 'Fatal error:' ) ) { self::log_message( ' -> Detected uncaught fatal error.' ); $site_response['php_fatal'] = true; } else { self::log_message( ' -> No uncaught fatal error detected.' ); $site_response['php_fatal'] = false; } } else { self::log_message( ' -> ' . $response['body'] ); $site_response['php_fatal'] = true; } return $site_response; } /** * Capture basic operating details * * We do this via CURL for access to CURLOPT_RESOLVE, which is needed in * order to skip around DNS issues. * * @param string $check_url URL to check. * @return array status_code (int), body (html) */ private static function get_site_response( $check_url ) { $timeout = 30; $ip = getenv( 'RESOLVE_DOMAIN' ); $parsed_url = wp_parse_url( $check_url ); $ch = curl_init(); curl_setopt( $ch, CURLOPT_URL, $check_url ); if ( false !== $ip ) { curl_setopt( $ch, CURLOPT_RESOLVE, array( 'www.' . $parsed_url['host'] . ':443:' . $ip, $parsed_url['host'] . ':443:' . $ip, 'www.' . $parsed_url['host'] . ':80:' . $ip, $parsed_url['host'] . ':80:' . $ip, ) ); } curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout ); curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 ); curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 ); // Get the data we need. $raw_body = curl_exec( $ch ); $http_respond = trim( strip_tags( $raw_body ) ); $http_code = curl_getinfo( $ch, CURLINFO_RESPONSE_CODE ); $header_size = curl_getinfo( $ch, CURLINFO_HEADER_SIZE ); $body = substr( $raw_body, $header_size ); curl_close( $ch ); // Build array. $response = array( 'status_code' => (int) $http_code, 'body' => $body, ); return $response; } /** * A basic CURL check first * * @param string $url URL to check. */ private static function url_test( $url ) { // Get IP from environment variable. $ip = getenv( 'RESOLVE_DOMAIN' ); // parse URL. $parsed_url = wp_parse_url( $url ); // Echo response for debugging. self::log_message( ' -> URL to test: ' . $url ); // Counter - how many times will we retry? $retry = 0; // Curl timeout - 30 second default, was 10 $timeout = 30; // Try to check curl results 3 times. while ( $retry < 3 ) { $ch = curl_init(); curl_setopt( $ch, CURLOPT_URL, $url ); if ( false !== $ip ) { curl_setopt( $ch, CURLOPT_RESOLVE, array( $ip ) ); curl_setopt( $ch, CURLOPT_RESOLVE, array( 'www.' . $parsed_url['host'] . ':443:' . $ip, $parsed_url['host'] . ':443:' . $ip, 'www.' . $parsed_url['host'] . ':80:' . $ip, $parsed_url['host'] . ':80:' . $ip, ) ); } curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout ); curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 ); curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 ); $http_respond = curl_exec( $ch ); $http_respond = trim( strip_tags( $http_respond ) ); $http_code = curl_getinfo( $ch, CURLINFO_RESPONSE_CODE ); curl_close( $ch ); // Echo response for debugging. self::log_message( ' -> URL Test Response: ' . $http_code ); if ( ( ( (int) $http_code < 400 ) && ( 0 !== (int) $http_code ) ) || in_array( $http_code, self::valid_http_codes() ) ) { $return = true; $retry = 5; // higher than what we test for to break loop. } else { $return = false; $retry++; sleep( 2 ); // sleep 2 seconds and retry if needed.... } } return $return; } }