Completed
Push — add/vr-shortcode ( 271979...022ee9 )
by
unknown
26:28 queued 20:24
created

class.jetpack-autoupdate.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Handles items that have been selected for automatic updates.
5
 * Hooks into WP_Automatic_Updater
6
 */
7
class Jetpack_Autoupdate {
8
9
	public $updates_allowed;
10
	public $jetpack;
11
	public $autoupdate_results;
12
	public $is_updating = false;
13
14
	public $autoupdate_expected = array(
15
		'plugin'=> array(),
16
		'theme' => array(),
17
	);
18
19
	public $log = array(
20
		'plugin' => array(),
21
		'theme' => array(),
22
	);
23
24
	private static $instance = null;
25
26
	static function init() {
27
		if ( is_null( self::$instance ) ) {
28
			self::$instance = new Jetpack_Autoupdate;
29
		}
30
		return self::$instance;
31
	}
32
33
	private function __construct() {
34
		$this->updates_allowed = Jetpack::is_module_active( 'manage' );
35
36
		// Only run automatic updates if a user as opted in by activating the manage module.
37
		if ( $this->updates_allowed ) {
38
			add_filter( 'auto_update_plugin',  array( $this, 'autoupdate_plugin' ), 10, 2 );
39
			add_filter( 'auto_update_theme',   array( $this, 'autoupdate_theme' ), 10, 2 );
40
			add_filter( 'auto_update_core',    array( $this, 'autoupdate_core' ), 10, 2 );
41
			add_action( 'automatic_updates_complete', array( $this, 'automatic_updates_complete' ), 10, 1 );
42
			add_action( 'shutdown', array( $this, 'log_results' ) );
43
		}
44
45
		// Anytime WordPress saves update data, we'll want to update our Jetpack option as well.
46
		if ( is_main_site() ) {
47
			add_action( 'set_site_transient_update_plugins', array( $this, 'save_update_data' ) );
48
			add_action( 'set_site_transient_update_themes', array( $this, 'save_update_data' ) );
49
			add_action( 'set_site_transient_update_core', array( $this, 'save_update_data' ) );
50
		}
51
52
	}
53
54 View Code Duplication
	function autoupdate_plugin( $update, $item ) {
55
		$autoupdate_plugin_list = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
56
		if ( in_array( $item->plugin, $autoupdate_plugin_list ) ) {
57
			$this->expect( $item->plugin );
58
 			return true;
59
		}
60
61
		return $update;
62
	}
63
64 View Code Duplication
	function autoupdate_theme( $update, $item ) {
65
		$autoupdate_theme_list = Jetpack_Options::get_option( 'autoupdate_themes', array() );
66
		if ( in_array( $item->theme , $autoupdate_theme_list) ) {
67
			$this->expect( $item->theme, $type = 'theme' );
68
			return true;
69
		}
70
		return $update;
71
	}
72
73
	function autoupdate_core( $update, $item ) {
0 ignored issues
show
The parameter $item is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
74
		$autoupdate_core = Jetpack_Options::get_option( 'autoupdate_core', false );
75
		if ( $autoupdate_core ) {
76
			return $autoupdate_core;
77
		}
78
		return $update;
79
	}
80
81
	/**
82
	 * Stores the an item identifier to the autoupdate_expected array.
83
	 *
84
	 * @param string $item  Example: 'jetpack/jetpack.php' for type 'plugin' or 'twentyfifteen' for type 'theme'
85
	 * @param string $type 'plugin' or 'theme'
86
	 */
87
	function expect( $item, $type='plugin' ) {
88
		$this->is_updating = true;
89
		$this->autoupdate_expected[ $type ][] = $item;
90
	}
91
92
	/**
93
	 * Calculates available updates and saves them to a Jetpack Option
94
	 * Update data is saved in the following schema:
95
	 *
96
	 * array (
97
	 *      'plugins'                       => (int) number of plugin updates available
98
	 *      'themes'                        => (int) number of theme updates available
99
	 *      'wordpress'                     => (int) number of wordpress core updates available
100
	 *      'translations'                  => (int) number of translation updates available
101
	 *      'total'                         => (int) total of all available updates
102
	 *      'wp_version'                    => (string) the current version of WordPress that is running
103
	 *      'wp_update_version'             => (string) the latest available version of WordPress, only present if a WordPress update is needed
104
	 *      'site_is_version_controlled'    => (bool) is the site under version control
105
	 * )
106
	 */
107
	function save_update_data() {
108
		global $wp_version;
109
110
		$update_data = wp_get_update_data();
111
112
		// Stores the individual update counts as well as the total count.
113
		if ( isset( $update_data['counts'] ) ) {
114
			$updates = $update_data['counts'];
115
		}
116
117
		// Stores the current version of WordPress.
118
		$updates['wp_version'] = $wp_version;
0 ignored issues
show
The variable $updates does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
119
120
		// If we need to update WordPress core, let's find the latest version number.
121 View Code Duplication
		if ( ! empty( $updates['wordpress'] ) ) {
122
			$cur = get_preferred_from_update_core();
123
			if ( isset( $cur->response ) && 'upgrade' === $cur->response ) {
124
				$updates['wp_update_version'] = $cur->current;
125
			}
126
		}
127
128
		$updates['site_is_version_controlled'] = (bool) $this->is_version_controlled();
129
		Jetpack_Options::update_option( 'updates', $updates );
130
	}
131
132
	/**
133
	 * Finds out if a site is using a version control system.
134
	 * We'll store that information as a transient with a 24 expiration.
135
	 * We only need to check once per day.
136
	 *
137
	 * @return string ( '1' | '0' )
138
	 */
139
	function is_version_controlled() {
140
		$is_version_controlled = get_transient( 'jetpack_site_is_vcs' );
141
142
		if ( false === $is_version_controlled ) {
143
			include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
144
			$updater = new WP_Automatic_Updater();
145
			$is_version_controlled  = strval( $updater->is_vcs_checkout( $context = ABSPATH ) );
146
			// transients should not be empty
147
			if ( empty( $is_version_controlled ) ) {
148
				$is_version_controlled = '0';
149
			}
150
			set_transient( 'jetpack_site_is_vcs', $is_version_controlled, DAY_IN_SECONDS );
151
		}
152
153
		return $is_version_controlled;
154
	}
155
156
	/**
157
	 * On completion of an automatic update, let's store the results.
158
	 *
159
	 * @param $results - Sent by WP_Automatic_Updater after it completes an autoupdate action. Results may be empty.
160
	 */
161
	function automatic_updates_complete( $results ) {
162
		$this->autoupdate_results = $results;
163
	}
164
165
	/**
166
	 * On shutdown, let's check to see if we've preformed an automatic update.
167
	 * If so, let's compare the expected results to the actual results, and log our findings.
168
	 *
169
	 * Results are logged locally via Jetpack::log(), and globally via Jetpack::do_stats()
170
	 */
171
	function log_results() {
172
173
		if ( $this->is_updating ) {
174
175
			$this->jetpack = Jetpack::init();
176
			$items_to_log = array( 'plugin', 'theme' );
177
178
			foreach( $items_to_log as $items ) {
179
				$this->log_items( $items );
180
			}
181
182
			$this->jetpack->do_stats( 'server_side' );
183
			$this->jetpack->log( 'autoupdates', $this->log );
184
		}
185
	}
186
187
	/**
188
	 * Iterates through expected items ( plugins or themes ) and compares them to actual results.
189
	 *
190
	 * @param $items 'plugin' or 'theme'
191
	 */
192
	function log_items( $items ) {
193
		$items_updated = 0;
194
		$items_failed  = 0;
195
		$item_results  = $this->get_successful_updates( $items );
196
197
		foreach( $this->autoupdate_expected[ $items ] as $item ) {
198
			if ( in_array( $item, $item_results ) ) {
199
				$items_updated++;
200
				$this->log[ $items ][ $item ] = true;
201
			} else {
202
				$items_failed++;
203
				$this->log[ $items ][ $item ] = new WP_Error( "$items-fail", $this->get_error_message( $item, $type = $items ) );
204
			}
205
		}
206
207
		if ( $items_updated ) {
208
			$this->jetpack->stat( "autoupdates/$items-success", $items_updated );
209
		}
210
211
		if ( $items_failed ) {
212
			$this->jetpack->stat( "autoupdates/$items-fail", $items_failed );
213
		}
214
215
	}
216
217
	/**
218
	 * Parses the autoupdate results generated by WP_Automatic_Updater and returns a simple array of successful items
219
	 *
220
	 * @param string $type 'plugin' or 'theme'
221
	 *
222
	 * @return array
223
	 */
224
	private function get_successful_updates( $type = 'plugin' ) {
225
		$successful_updates = array();
226
227
		if ( ! isset( $this->autoupdate_results[ $type ] ) ) {
228
			return $successful_updates;
229
		}
230
231
		foreach( $this->autoupdate_results[ $type ] as $result ) {
232
			if ( $result->result ) {
233 View Code Duplication
				switch( $type ) {
234
					case 'theme':
235
						$successful_updates[] = $result->item->theme;
236
						break;
237
					default:
238
						$successful_updates[] = $result->item->plugin;
239
				}
240
			}
241
		}
242
243
		return $successful_updates;
244
	}
245
246
	/**
247
	 * Cycles through results generated by WP_Automatic_Updater to find the messages for the given item and item type.
248
	 *
249
	 * @param $item Example: 'jetpack/jetpack.php' for type 'plugin' or 'twentyfifteen' for type 'theme'
250
	 * @param string $type 'plugin' or 'theme'
251
	 *
252
	 * @return bool|string
253
	 */
254
	private function get_error_message( $item, $type = 'plugin' ) {
255
		if ( ! isset( $this->autoupdate_results[ $type ] ) ) {
256
			return false;
257
		}
258
		foreach( $this->autoupdate_results[ $type ] as $result ) {
259 View Code Duplication
			switch( $type ) {
260
				case 'theme':
261
					$id = $result->item->theme;
262
					break;
263
				default:
264
					$id = $result->item->plugin;
265
			}
266
			if ( $id == $item && isset( $result->messages ) ) {
267
				return implode( ', ', $result->messages );
268
			}
269
		}
270
		return false;
271
	}
272
273
}
274
Jetpack_Autoupdate::init();