GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

core.php ➔ update()   F
last analyzed

Complexity

Conditions 54
Paths > 20000

Size

Total Lines 285
Code Lines 131

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 54
eloc 131
nc 748224
nop 0
dl 0
loc 285
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace HM\BackUpWordPress;
4
5
/**
6
 * Handles anything that needs to be
7
 * done when the plugin is updated
8
 */
9
function update() {
10
11
	// Update from backUpWordPress 0.4.5
12
	if ( get_option( 'bkpwp_max_backups' ) ) {
13
14
		// Carry over the custom path
15
		if ( $legacy_path = get_option( 'bkpwppath' ) ) {
16
			update_option( 'hmbkp_path', $legacy_path );
17
		}
18
19
		// Options to remove
20
		$legacy_options = array(
21
			'bkpwp_archive_types',
22
			'bkpwp_automail_from',
23
			'bkpwp_domain',
24
			'bkpwp_domain_path',
25
			'bkpwp_easy_mode',
26
			'bkpwp_excludelists',
27
			'bkpwp_install_user',
28
			'bkpwp_listmax_backups',
29
			'bkpwp_max_backups',
30
			'bkpwp_presets',
31
			'bkpwp_reccurrences',
32
			'bkpwp_schedules',
33
			'bkpwp_calculation',
34
			'bkpwppath',
35
			'bkpwp_status_config',
36
			'bkpwp_status',
37
		);
38
39
		foreach ( $legacy_options as $option ) {
40
			delete_option( $option );
41
		}
42
43
		global $wp_roles;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
44
45
		$wp_roles->remove_cap( 'administrator', 'manage_backups' );
46
		$wp_roles->remove_cap( 'administrator', 'download_backups' );
47
48
		wp_clear_scheduled_hook( 'bkpwp_schedule_bkpwp_hook' );
49
50
	}
51
52
	// Version 1 to 2
53
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '2.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
54
55
		/**
56
		 * Setup a backwards compatible schedule
57
		 */
58
		$legacy_schedule = new Scheduled_Backup( 'backup' );
59
60
		// Backup type
61
		if ( ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY ) || get_option( 'hmbkp_files_only' ) ) {
62
			$legacy_schedule->set_type( 'file' );
63
		} elseif ( ( defined( 'HMBKP_DATABASE_ONLY' ) && HMBKP_DATABASE_ONLY ) || get_option( 'hmbkp_database_only' ) ) {
64
			$legacy_schedule->set_type( 'database' );
65
		} else {
66
			$legacy_schedule->set_type( 'complete' );
67
		}
68
69
		// Daily schedule time
70
		if ( defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) && HMBKP_DAILY_SCHEDULE_TIME ) {
71
			$legacy_schedule->set_schedule_start_time( strtotime( HMBKP_DAILY_SCHEDULE_TIME ) );
72
		}
73
74
		// Backup schedule
75
		$legacy_schedule->set_reoccurrence( get_option( 'hmbkp_schedule_frequency', 'daily' ) );
76
77
		// Automatic backups disabled?
78
		if ( ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) && HMBKP_DISABLE_AUTOMATIC_BACKUP ) || get_option( 'hmbkp_disable_automatic_backup' ) ) {
79
			$legacy_schedule->set_reoccurrence( 'manually' );
80
		}
81
82
		// Max backups
83
		if ( defined( 'HMBKP_MAX_BACKUPS' ) && is_numeric( HMBKP_MAX_BACKUPS ) ) {
84
			$legacy_schedule->set_max_backups( (int) HMBKP_MAX_BACKUPS );
85
		} else {
86
			$legacy_schedule->set_max_backups( (int) get_option( 'hmbkp_max_backups', 10 ) );
87
		}
88
89
		// Excludes
90
		if ( get_option( 'hmbkp_excludes' ) ) {
91
			$legacy_schedule->set_excludes( get_option( 'hmbkp_excludes' ) );
92
		}
93
94
		// Backup email
95
		if ( defined( 'HMBKP_EMAIL' ) && is_email( HMBKP_EMAIL ) ) {
96
			$legacy_schedule->set_service_options( 'HMBKP_Email_Service', array( 'email' => HMBKP_EMAIL ) );
97
		} elseif ( is_email( get_option( 'hmbkp_email_address' ) ) ) {
98
			$legacy_schedule->set_service_options( 'HMBKP_Email_Service', array( 'email' => get_option( 'hmbkp_email_address' ) ) );
99
		}
100
101
		// Set the archive filename to what it used to be
102
		$legacy_schedule->backup_filename = implode( '-', array( get_bloginfo( 'name' ), 'backup', current_time( 'Y-m-d-H-i-s' ) ) ) . '.zip';
103
104
		$legacy_schedule->save();
105
106
		$legacy_path = get_option( 'hmbkp_path' );
107
108
		if ( $legacy_path ) {
109
110
			// Prepend 'backup-' to the beginning of any legacy backups so they are picked up by the legacy schedule
111
			if ( $handle = opendir( $legacy_path ) ) {
112
				while ( false !== ( $file = readdir( $handle ) ) ) {
113
					if ( 'zip' === pathinfo( $file, PATHINFO_EXTENSION ) ) {
114
						rename( trailingslashit( $legacy_path ) . $file, trailingslashit( $legacy_path ) . 'backup-' . $file );
115
					}
116
				}
117
				closedir( $handle );
118
			}
119
120
			PATH::get_instance()->move_old_backups( $legacy_path );
121
122
		}
123
124
		// Remove the legacy options
125
		foreach ( array( 'hmbkp_database_only', 'hmbkp_files_only', 'hmbkp_max_backups', 'hmbkp_email_address', 'hmbkp_email', 'hmbkp_schedule_frequency', 'hmbkp_disable_automatic_backup' ) as $option_name ) {
126
			delete_option( $option_name );
127
		}
128
	}
129
130
	// Update from 2.x to 3.0
131
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '2.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
132
133
		// Remove the plugin data cache
134
		delete_transient( 'hmbkp_plugin_data' );
135
136
	}
137
138
	// Update to 3.1
139
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
140
141
		// Remove the plugin data cache
142
		delete_option( 'hmbkp_path' );
143
		delete_option( 'hmbkp_default_path' );
144
145
	}
146
147
	// update to 3.1.4
148
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.1.4', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
149
150
		$old_option_names = array(
151
			'HM\BackUpWordPressDropbox\Dropbox_Service'    => 'dropbox',
152
			'HMBKP_DX_Backup_Service'                      => 'dropbox',
153
			'HM\BackUpWordPressFTP\FTP_Backup_Service'     => 'ftp',
154
			'HMBKP_FTP_Backup_Service'                     => 'ftp',
155
			'HM\BackUpWordPressGDrive\Google_Drive_BackUp' => 'google-drive',
156
			'HMBKP_GDV_Backup_Service'                     => 'google-drive',
157
			'HM\BackUpWordPressRackspace\RackSpace_BackUp' => 'rackspace-cloud',
158
			'HMBKP_RSC_Backup_Service'                     => 'rackspace-cloud',
159
			'HM\BackUpWordPressS3\S3_Backup'               => 's3',
160
			'HMBKP_S3_Backup_Service'                      => 's3',
161
			'HM\BackUpWordPressWinAzure\WinAzure_Backup'   => 'azure',
162
			'HMBKP_WAZ_Backup_Service'                     => 'azure',
163
			'HM\BackUpWordPress\Email_Service'             => 'email',
164
		);
165
166
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
167
168
		// Get all schedule options with a SELECT query and delete them.
169
		$schedules = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s", 'hmbkp_schedule_%' ) );
170
171
		if ( 0 < count( $schedules ) ) {
172
173
			// Access each schedules settings to see if the addon settings names need to be be updated to the new naming convention which uses the service slug generated from the $name property.
174
			foreach ( $schedules as $schedule_id ) {
175
176
				// Load the settings for this schedule into an array
177
				// so we can loop through the different service settings
178
				$schedule_settings = get_option( $schedule_id );
179
180
				// Iterate over each schedule setting for this schedule and check its name against our array.
181
				foreach ( $schedule_settings as $key => $val ) {
182
					// Find the current element key in our control array and get its value. Set a new element in the settings array with the found value as its key. Aka rename the element key
183
					if ( array_key_exists( $key, $old_option_names ) ) {
184
185
						// move the value to our new key
186
						$schedule_settings[ $old_option_names[ $key ] ] = $schedule_settings[ $key ];
187
188
						unset( $schedule_settings[ $key ] );
189
190
					}
191
				}
192
193
				// Save back to the DB
194
				update_option( $schedule_id, $schedule_settings );
195
			}
196
		}
197
	}
198
199
	// Update to 3.1.5
200
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.1.5', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
201
202
		// Delete all transients
203
		$transients = array(
204
			'hmbkp_plugin_data',
205
			'hmbkp_directory_filesizes',
206
			'hmbkp_directory_filesizes_running',
207
			'hmbkp_wp_cron_test_beacon',
208
			'hm_backdrop',
209
		);
210
211
		array_map( 'delete_transient', $transients );
212
213
		// Clear duplicate schedules on multisite
214
		if ( is_multisite() ) {
215
216
			// get current blogs from DB
217
			$blogs = wp_get_sites();
218
219
			foreach ( $blogs as $blog ) {
220
221
				switch_to_blog( get_current_blog_id() );
222
223
				if ( is_main_site( get_current_blog_id() ) ) {
224
					continue;
225
				}
226
227
				global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
228
229
				// Get the schedule options
230
				$schedules = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s", 'hmbkp_schedule_%' ) );
231
232
				// clear schedules
233
				foreach ( array_map( function ( $item ) {
234
					return ltrim( $item, 'hmbkp_schedule_' );
235
				}, $schedules ) as $item ) {
236
					wp_clear_scheduled_hook( 'hmbkp_schedule_hook', array( 'id' => $item ) );
237
				}
238
239
				// delete options
240
				array_map( 'delete_option', $schedules );
241
242
				array_map( 'delete_option', array( 'hmbkp_enable_support', 'hmbkp_plugin_version', 'hmbkp_path', 'hmbkp_default_path', 'hmbkp_upsell' ) );
243
244
				// Delete all transients
245
				array_map( 'delete_transient', array( 'hmbkp_plugin_data', 'hmbkp_directory_filesizes', 'hmbkp_directory_filesize_running', 'timeout_hmbkp_wp_cron_test_beacon', 'hmbkp_wp_cron_test_beacon' ) );
246
247
			}
248
249
			restore_current_blog();
250
		}
251
	}
252
253
	// Update from 3.3.0
254
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.3.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
255
256
		$schedules = Schedules::get_instance();
257
258
		// Loop through all schedules and re-set the reccurrence to include hmbkp_
259
		foreach ( $schedules->get_schedules() as $schedule ) {
260
261
			$reoccurrence = $schedule->get_reoccurrence();
262
263
			if ( 'manually' !== $reoccurrence && strpos( $reoccurrence, 'hmbkp_' ) === 0 ) {
264
				$schedule->set_reoccurrence( substr( $reoccurrence, 6 ) );
265
			}
266
267
			$schedule->save();
268
269
		}
270
	}
271
272
	// Update from 3.3.4
273
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( '3.4.0', get_option( 'hmbkp_plugin_version' ), '>' ) ) {
274
		delete_transient( 'hmbkp_directory_filesizes' );
275
	}
276
277
	// Every update
278
	if ( get_option( 'hmbkp_plugin_version' ) && version_compare( Plugin::PLUGIN_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
279
280
		require_once( HMBKP_PLUGIN_PATH . 'classes/class-setup.php' );
281
282
		\HMBKP_Setup::deactivate();
283
284
		Path::get_instance()->protect_path( 'reset' );
285
286
	}
287
288
	// Update the stored version
289
	if ( get_option( 'hmbkp_plugin_version' ) !== Plugin::PLUGIN_VERSION ) {
290
		update_option( 'hmbkp_plugin_version', Plugin::PLUGIN_VERSION );
291
	}
292
293
}
294
295
/**
296
 * Setup the default backup schedules
297
 */
298
function setup_default_schedules() {
299
300
	$schedules = Schedules::get_instance();
301
302
	if ( $schedules->get_schedules() ) {
303
		return;
304
	}
305
306
	/**
307
	 * Schedule a database backup daily and store backups
308
	 * for the last 2 weeks
309
	 */
310
	$database_daily = new Scheduled_Backup( (string) time() );
311
	$database_daily->set_type( 'database' );
312
	$database_daily->set_schedule_start_time( determine_start_time( 'daily', array( 'hours' => '23', 'minutes' => '0' ) ) );
313
	$database_daily->set_reoccurrence( 'daily' );
314
	$database_daily->set_max_backups( 7 );
315
	$database_daily->save();
316
317
	/**
318
	 * Schedule a complete backup to run weekly and store backups for
319
	 * the last 3 months
320
	 */
321
	$complete_weekly = new Scheduled_Backup( (string) ( time() + 1 ) );
322
	$complete_weekly->set_type( 'complete' );
323
	$complete_weekly->set_schedule_start_time( determine_start_time( 'weekly', array( 'day_of_week' => 'sunday', 'hours' => '3', 'minutes' => '0' ) ) );
324
	$complete_weekly->set_reoccurrence( 'weekly' );
325
	$complete_weekly->set_max_backups( 3 );
326
	$complete_weekly->save();
327
328
	$schedules->refresh_schedules();
329
330
	add_action( 'admin_notices', function() {
331
		echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has set up your default schedules.', 'backupwordpress' ) . '</strong> ' . __( 'By default BackUpWordPress performs a daily backup of your database and a weekly backup of your database &amp; files. You can modify these schedules.', 'backupwordpress' ) . '</p></div>';
332
	} );
333
334
}
335
336
add_action( 'admin_init', '\HM\BackUpWordPress\setup_default_schedules', 11 );
337
338
/**
339
 * Return an array of cron schedules
340
 *
341
 * @param $schedules
342
 * @return array $reccurrences
343
 */
344
function cron_schedules( $schedules = array() ) {
345
346
	$schedules += array(
347
		'hourly'      => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly', 'backupwordpress' ) ),
348
		'twicedaily'  => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily', 'backupwordpress' ) ),
349
		'daily'       => array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once Daily', 'backupwordpress' ) ),
350
		'weekly'      => array( 'interval' => WEEK_IN_SECONDS, 'display' => __( 'Once Weekly', 'backupwordpress' ) ),
351
		'fortnightly' => array( 'interval' => 2 * WEEK_IN_SECONDS, 'display' => __( 'Once Every Two Weeks', 'backupwordpress' ) ),
352
		'monthly'     => array( 'interval' => 30 * DAY_IN_SECONDS, 'display' => __( 'Once Monthly', 'backupwordpress' ) ),
353
	);
354
355
	return $schedules;
356
}
357
358
add_filter( 'cron_schedules', '\HM\BackUpWordPress\cron_schedules' );
359
360
/**
361
 * Recursively delete a directory including
362
 * all the files and sub-directories.
363
 *
364
 * @param string $dir
365
 * @return bool
366
 * @return bool|WP_Error
367
 */
368
function rmdirtree( $dir ) {
369
370
	if ( false !== strpos( Path::get_home_path(), $dir ) ) {
371
		return new WP_Error( 'hmbkp_invalid_action_error', sprintf( __( 'You can only delete directories inside your WordPress installation', 'backupwordpress' ) ) );
372
	}
373
374
	if ( is_file( $dir ) ) {
375
		@unlink( $dir );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
376
	}
377
378
	if ( ! is_dir( $dir ) || ! is_readable( $dir ) ) {
379
		return false;
380
	}
381
382
	$files = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $dir, \RecursiveDirectoryIterator::SKIP_DOTS ), \RecursiveIteratorIterator::CHILD_FIRST, \RecursiveIteratorIterator::CATCH_GET_CHILD );
383
384
	foreach ( $files as $file ) {
385
386
		if ( $file->isDir() ) {
387
			@rmdir( $file->getPathname() );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
388
		} else {
389
			@unlink( $file->getPathname() );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
390
		}
391
	}
392
393
	@rmdir( $dir );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
394
395
	return true;
396
}
397
398
/**
399
 * Check if a backup is possible with regards to file
400
 * permissions etc.
401
 *
402
 * @return bool
403
 */
404
function is_backup_possible() {
405
406
	if ( ! wp_is_writable( Path::get_path() ) || ! is_dir( Path::get_path() ) ) {
407
		return false;
408
	}
409
410
	if ( ! is_readable( Path::get_root() ) ) {
411
		return false;
412
	}
413
414
	if ( ! Requirement_Mysqldump_Command_Path::test() && ! Requirement_PDO::test() ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \HM\BackUpWordPress\Requ...mp_Command_Path::test() of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
Bug Best Practice introduced by
The expression \HM\BackUpWordPress\Requirement_PDO::test() of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
415
		return false;
416
	}
417
418
	if ( ! Requirement_Zip_Command_Path::test() && ! Requirement_Zip_Archive::test() ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \HM\BackUpWordPress\Requ...ip_Command_Path::test() of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
419
		return false;
420
	}
421
422
	return true;
423
}
424
425
/**
426
 * Get the max email attachment filesize
427
 *
428
 * Can be overridden by defining HMBKP_ATTACHMENT_MAX_FILESIZE
429
 *
430
 * return int the filesize
431
 */
432
function get_max_attachment_size() {
433
434
	$max_size = '10mb';
435
436
	if ( defined( 'HMBKP_ATTACHMENT_MAX_FILESIZE' ) && wp_convert_hr_to_bytes( HMBKP_ATTACHMENT_MAX_FILESIZE ) ) {
437
		$max_size = HMBKP_ATTACHMENT_MAX_FILESIZE;
438
	}
439
440
	return wp_convert_hr_to_bytes( $max_size );
441
442
}
443
444
function is_path_accessible( $dir ) {
445
446
	// Path is inaccessible
447
	if ( strpos( $dir, Path::get_home_path() ) === false ) {
448
		return false;
449
	}
450
451
	return true;
452
}
453
454
/**
455
 * List of schedules
456
 *
457
 * @return array
458
 */
459
function get_cron_schedules() {
460
	return cron_schedules();
461
}
462
463
/**
464
 * @param string $type the type of the schedule
465
 * @param array $times {
466
 *     An array of time arguments. Optional.
467
 *
468
 *     @type int $minutes          The minute to start the schedule on. Defaults to current time + 10 minutes. Accepts
469
 *                                 any valid `date( 'i' )` output.
470
 *     @type int $hours            The hour to start the schedule on. Defaults to current time + 10 minutes. Accepts
471
 *                                 any valid `date( 'G' )` output.
472
 *     @type string $day_of_week   The day of the week to start the schedule on. Defaults to current time + 10 minutes. Accepts
473
 *                                 any valid `date( 'l' )` output.
474
 *     @type int $day_of_month     The day of the month to start the schedule on. Defaults to current time + 10 minutes. Accepts
475
 *                                 any valid `date( 'j' )` output.
476
 *     @type int $now              The current time. Defaults to `time()`. Accepts any valid timestamp.
477
 *
478
 * }
479
 * @return int $timestamp Returns the resulting timestamp on success and Int 0 on failure
480
 */
481
function determine_start_time( $type, $times = array() ) {
482
483
	// Default to in 10 minutes
484
	if ( ! empty( $times['now'] ) ) {
485
		$default_timestamp = $times['now'] + 600;
486
487
	} else {
488
		$default_timestamp = time() + 600;
489
	}
490
491
	$default_times = array(
492
		'minutes'      => date( 'i', $default_timestamp ),
493
		'hours'        => date( 'G', $default_timestamp ),
494
		'day_of_week'  => date( 'l', $default_timestamp ),
495
		'day_of_month' => date( 'j', $default_timestamp ),
496
		'now'          => time(),
497
	);
498
499
	$args = wp_parse_args( $times, $default_times );
500
501
	$intervals = get_cron_schedules();
502
503
	// Allow the hours and minutes to be overwritten by a constant
504
	if ( defined( 'HMBKP_SCHEDULE_TIME' ) && HMBKP_SCHEDULE_TIME ) {
505
		$hm = HMBKP_SCHEDULE_TIME;
506
	} else { // The hour and minute that the schedule should start on
507
		$hm = $args['hours'] . ':' . $args['minutes'] . ':00';
508
	}
509
510
	switch ( $type ) {
511
512
		case 'hourly' :
513
		case 'daily' :
514
		case 'twicedaily':
515
516
			// The next occurance of the specified time
517
			$schedule_start = $hm;
518
			break;
519
520
		case 'weekly' :
521
		case 'fortnightly' :
522
523
			// The next day of the week at the specified time
524
			$schedule_start = $args['day_of_week'] . ' ' . $hm;
525
			break;
526
527
		case 'monthly' :
528
529
			// The occurance of the time on the specified day of the month
530
			$schedule_start = date( 'F', $args['now'] ) . ' ' . $args['day_of_month'] . ' ' . $hm;
531
532
			// If we've already gone past that day this month then we'll need to start next month
533
			if ( strtotime( $schedule_start, $args['now'] ) <= $args['now'] ) {
534
				$schedule_start = date( 'F', strtotime( '+ 1 month', $args['now'] ) )  . ' ' . $args['day_of_month'] . ' ' . $hm;
535
			}
536
537
			// If that's still in the past then we'll need to jump to next year
538
			if ( strtotime( $schedule_start, $args['now'] ) <= $args['now'] ) {
539
				$schedule_start = date( 'F', strtotime( '+ 1 month', $args['now'] ) )  . ' ' . $args['day_of_month'] . ' ' . date( 'Y', strtotime( '+ 1 year', $args['now'] ) ) . ' ' . $hm;
540
			}
541
542
			break;
543
544
		default :
545
546
			return 0;
547
548
	}
549
550
	$timestamp = strtotime( $schedule_start, $args['now'] );
551
552
	// Convert to UTC
553
	$timestamp -= get_option( 'gmt_offset' ) * 3600;
554
555
	// If the scheduled time already passed then keep adding the interval until we get to a future date
556
	while ( $timestamp <= $args['now'] ) {
557
		$timestamp += $intervals[ $type ]['interval'];
558
	}
559
560
	return $timestamp;
561
562
}
563
564
/**
565
 * Helper function for creating safe action URLs.
566
 *
567
 * @param string $action Callback function name.
568
 * @param array $query_args Additional GET params.
569
 *
570
 * @return string
571
 */
572
function admin_action_url( $action, array $query_args = array() ) {
573
574
	$query_args = array_merge( $query_args, array( 'action' => 'hmbkp_' . $action ) );
575
576
	return esc_url( wp_nonce_url( add_query_arg( $query_args, admin_url( 'admin-post.php' ) ), 'hmbkp_' . $action, 'hmbkp-' . $action . '_nonce' ) );
577
}
578
579
/**
580
 * OS dependant way to pipe stderr to null
581
 *
582
 * @return string The exec argument to pipe stderr to null
583
 */
584
function ignore_stderr() {
585
586
	// If we're on Windows
587
	if ( DIRECTORY_SEPARATOR == '\\' ) {
588
		return '2>nul';
589
	}
590
591
	// Or Unix
592
	return '2>/dev/null';
593
594
}
595
596
/**
597
 * Return the contents of `$directory` as a single depth list ordered by total filesize.
598
 *
599
 * Will schedule background threads to recursively calculate the filesize of subdirectories.
600
 * The total filesize of each directory and subdirectory is cached in a transient for 1 week.
601
 *
602
 * @param string $directory The directory to list
603
 *
604
 * @todo doesn't really belong in this class, should just be a function
605
 * @return array            returns an array of files ordered by filesize
606
 */
607
function list_directory_by_total_filesize( $directory, Excludes $excludes ) {
608
609
	$files = $files_with_no_size = $empty_files = $files_with_size = $unreadable_files = array();
610
611
	if ( ! is_dir( $directory ) ) {
612
		return $files;
613
	}
614
615
	$finder = new \Symfony\Component\Finder\Finder();
616
	$finder->followLinks();
617
	$finder->ignoreDotFiles( false );
618
	$finder->ignoreUnreadableDirs();
619
	$finder->depth( '== 0' );
620
621
	$site_size = new Site_Size( 'file', $excludes );
622
623
	$files = $finder->in( $directory );
624
625
	foreach ( $files as $entry ) {
626
627
		// Get the total filesize for each file and directory
628
		$filesize = $site_size->filesize( $entry );
629
630
		if ( $filesize ) {
631
632
			// If there is already a file with exactly the same filesize then let's keep increasing the filesize of this one until we don't have a clash
633
			while ( array_key_exists( $filesize, $files_with_size ) ) {
634
				$filesize ++;
635
			}
636
637
			$files_with_size[ $filesize ] = $entry;
638
639
		} elseif ( 0 === $filesize ) {
640
			$empty_files[] = $entry;
641
		} else {
642
			$files_with_no_size[] = $entry;
643
		}
644
	}
645
646
	// Sort files by filesize, largest first
647
	krsort( $files_with_size );
648
649
	// Add 0 byte files / directories to the bottom
650
	$files = $files_with_size + array_merge( $empty_files, $unreadable_files );
651
652
	// Add directories that are still calculating to the top
653
	if ( $files_with_no_size ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $files_with_no_size of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
654
655
		// We have to loop as merging or concatenating the array would re-flow the keys which we don't want because the filesize is stored in the key
656
		foreach ( $files_with_no_size as $entry ) {
657
			array_unshift( $files, $entry );
658
		}
659
	}
660
661
	return $files;
662
663
}
664