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.
Completed
Pull Request — master (#936)
by Tom
02:44
created

Site_Size   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 25
c 4
b 1
f 1
lcom 1
cbo 2
dl 0
loc 219
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B get_site_size() 0 32 5
A get_formatted_site_size() 0 3 1
A is_site_size_being_calculated() 0 3 1
A is_site_size_cached() 0 3 1
B recursive_filesize_scanner() 0 46 4
B filesize() 0 18 6
B directory_filesize() 0 28 4
A rebuild_directory_filesizes() 0 14 2
1
<?php
2
3
namespace HM\BackUpWordPress;
4
5
use HM\Backdrop\Task;
6
use Symfony\Component\Finder\Finder;
7
8
/**
9
 * Site Size class
10
 *
11
 * Use to calculate the total or partial size of the sites database and files.
12
 */
13
class Site_Size {
14
15
	private $size = 0;
16
	private $type = '';
17
	private $excludes = array();
18
19
	/**
20
	 * Constructor
21
	 *
22
	 * Set up some initial conditions including whether we want to calculate the
23
	 * size of the database, files or both and whether to exclude any files from
24
	 * the file size calculation.
25
	 *
26
	 * @param string $type     Whether to calculate the size of the database, files
27
	 *                         or both. Should be one of 'file', 'database' or 'complete'
28
	 * @param array  $excludes An array of exclude rules
0 ignored issues
show
Documentation introduced by
Should the type for parameter $excludes not be null|Excludes?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
29
	 */
30
	public function __construct( $type = 'complete', Excludes $excludes = null ) {
31
		$this->type = $type;
32
		$this->excludes = $excludes;
0 ignored issues
show
Documentation Bug introduced by
It seems like $excludes of type null or object<HM\BackUpWordPress\Excludes> is incompatible with the declared type array of property $excludes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
33
	}
34
35
	/**
36
	 * Calculate the size total size of the database + files.
37
	 *
38
	 * Doesn't account for any compression that would be gained by zipping.
39
	 *
40
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
41
	 */
42
	public function get_site_size() {
43
44
		if ( $this->size ) {
45
			return $this->size;
46
		}
47
48
		$size = 0;
49
50
		// Include database size except for file only schedule.
51
		if ( 'file' !== $this->type ) {
52
53
			global $wpdb;
54
			$tables = $wpdb->get_results( 'SHOW TABLE STATUS FROM `' . DB_NAME . '`', ARRAY_A );
55
56
			foreach ( $tables as $table ) {
57
				$size += (float) $table['Data_length'];
58
			}
59
		}
60
61
		// Include total size of dirs/files except for database only schedule.
62
		if ( 'database' !== $this->type ) {
63
64
			$root = new \SplFileInfo( Path::get_root() );
65
			$size += $this->filesize( $root );
66
67
		}
68
69
		$this->size = $size;
0 ignored issues
show
Documentation Bug introduced by
It seems like $size can also be of type double. However, the property $size is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
70
71
		return $size;
72
73
	}
74
75
	/**
76
	 * Get the site size formatted
77
	 *
78
	 * @see size_format
79
	 *
80
	 * @return string
81
	 */
82
	public function get_formatted_site_size() {
83
		return size_format( $this->get_site_size() );
84
	}
85
86
	/**
87
	 * Whether the total filesize is being calculated
88
	 *
89
	 * @return bool
90
	 */
91
	public static function is_site_size_being_calculated() {
92
		return false !== get_transient( 'hmbkp_directory_filesizes_running' );
93
	}
94
95
	/**
96
	 * Whether the total filesize is cached
97
	 *
98
	 * @return bool
99
	 */
100
	public static function is_site_size_cached() {
101
		return false !== get_transient( 'hmbkp_directory_filesizes' );
102
	}
103
104
	/**
105
	 * Recursively scans a directory to calculate the total filesize
106
	 *
107
	 * Locks should be set by the caller with `set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );`
108
	 *
109
	 * @return array $directory_sizes    An array of directory paths => filesize sum of all files in directory
110
	 */
111
	public function recursive_filesize_scanner() {
112
113
		/**
114
		 * Raise the `memory_limit` and `max_execution time`
115
		 *
116
		 * Respects the WP_MAX_MEMORY_LIMIT Constant and the `admin_memory_limit`
117
		 * filter.
118
		 */
119
		@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
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...
120
		@set_time_limit( 0 );
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...
121
122
		// Use the cached array directory sizes if available
123
		$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
124
125
		// If we do have it in cache then let's use it and also clear the lock
126
		if ( is_array( $directory_sizes ) ) {
127
			delete_transient( 'hmbkp_directory_filesizes_running' );
128
			return $directory_sizes;
129
		}
130
131
		// If we don't have it cached then we'll need to re-calculate
132
		$finder = new Finder();
133
		$finder->followLinks();
134
		$finder->ignoreDotFiles( false );
135
		$finder->ignoreUnreadableDirs( true );
136
137
		$files = $finder->in( Path::get_root() );
138
139
		foreach ( $files as $file ) {
140
141
			if ( $file->isReadable() ) {
142
				$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = $file->getSize();
143
			} else {
144
				$directory_sizes[ wp_normalize_path( $file->getRealpath() ) ] = 0;
145
			}
146
147
		}
148
149
		set_transient( 'hmbkp_directory_filesizes', $directory_sizes, DAY_IN_SECONDS );
150
151
		// Remove the lock
152
		delete_transient( 'hmbkp_directory_filesizes_running' );
153
154
		return $directory_sizes;
155
156
	}
157
158
	/**
159
	 * Get the total filesize for a given file or directory
160
	 *
161
	 * If $file is a file then just return the result of `filesize()`.
162
	 * If $file is a directory then recursively calculate the size.
163
	 *
164
	 * @param \SplFileInfo   $file The file or directory you want to know the size of
165
	 *
166
	 * @return int           The total filesize of the file or directory
167
	 */
168
	public function filesize( \SplFileInfo $file ) {
169
170
		// Skip missing or unreadable files
171
		if ( ! file_exists( $file->getPathname() ) || ! $file->getRealpath() || ! $file->isReadable() ) {
172
			return 0;
173
		}
174
175
		// If it's a file then just pass back the filesize
176
		if ( $file->isFile() ) {
177
			return $file->getSize();
178
		}
179
180
		// If it's a directory then pull it from the cached filesize array
181
		if ( $file->isDir() ) {
182
			return $this->directory_filesize( $file );
183
		}
184
185
	}
186
187
	public function directory_filesize( \SplFileInfo $file ) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
188
189
		// If we haven't calculated the site size yet then kick it off in a thread
190
		$directory_sizes = get_transient( 'hmbkp_directory_filesizes' );
191
192
193
		if ( ! is_array( $directory_sizes ) ) {
194
			$this->rebuild_directory_filesizes();
195
196
			// Intentionally return null so the caller can tell that the size is being calculated
197
			return null;
198
		}
199
200
		// The filepaths are stored in keys so we need to flip for use with preg_grep
201
		$directory_sizes = array_flip( preg_grep( '(' . wp_normalize_path( $file->getRealPath() ) . ')', array_flip( $directory_sizes ) ) );
202
203
		if ( $this->excludes ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->excludes 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...
204
			$excludes = implode( '|', $this->excludes->get_excludes_for_regex() );
0 ignored issues
show
Bug introduced by
The method get_excludes_for_regex cannot be called on $this->excludes (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
205
			if ( $excludes ) {
206
				// Use PREG_GREP_INVERT to remove any filepaths which match an exclude rule
207
				$directory_sizes = array_flip( preg_grep( '(' . $excludes . ')', array_flip( $directory_sizes ), PREG_GREP_INVERT ) );
208
			}
209
		}
210
211
		// Directory size is now just a sum of all files across all sub directories
212
		return absint( array_sum( $directory_sizes ) );
213
214
	}
215
216
	public function rebuild_directory_filesizes() {
217
218
		if ( $this->is_site_size_being_calculated() ) {
219
			return false;
220
		}
221
222
		// Mark the filesize as being calculated
223
		set_transient( 'hmbkp_directory_filesizes_running', true, HOUR_IN_SECONDS );
224
225
		// Schedule a Backdrop task to trigger a recalculation
226
		$task = new Task( array( $this, 'recursive_filesize_scanner' ) );
227
		$task->schedule();
228
229
	}
230
231
}
232