PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.1.3
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.1.3
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Filesystem / DiskWriteCheck.php
wp-staging / Framework / Filesystem Last commit date
Filters 2 years ago Scanning 5 years ago DebugLogReader.php 2 years ago DirectoryListing.php 3 years ago DiskWriteCheck.php 3 years ago FileObject.php 2 years ago Filesystem.php 2 years ago FilesystemExceptions.php 5 years ago FilterableDirectoryIterator.php 3 years ago LogCleanup.php 2 years ago LogFiles.php 2 years ago MissingFileException.php 3 years ago PathChecker.php 2 years ago PathIdentifier.php 2 years ago Permissions.php 5 years ago WpUploadsFolderSymlinker.php 4 years ago
DiskWriteCheck.php
143 lines
1 <?php
2
3 namespace WPStaging\Framework\Filesystem;
4
5 use WPStaging\Framework\Adapter\Directory;
6 use WPStaging\Backup\Exceptions\DiskNotWritableException;
7
8 class DiskWriteCheck
9 {
10 protected $directory;
11 protected $filesystem;
12 protected $reservedMemory;
13
14 const OPTION_DISK_WRITABLE_FAILED = 'wpstg_disk_writable_check_failed';
15
16 public function __construct(Filesystem $filesystem, Directory $directory)
17 {
18 $this->directory = $directory;
19 $this->filesystem = $filesystem;
20 // 1kb
21 $this->reservedMemory = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
22 }
23
24 /**
25 * @param string $path An absolute path to check for free disk space.
26 * @param int|float $bytesToStore The number of bytes intended to be written.
27 *
28 * @throws \RuntimeException When something happened that prevented us from checking if there's enough free disk space.
29 * @throws DiskNotWritableException When disk_free_space reports there's not enough disk space to store this amount of bytes.
30 */
31 public function checkPathCanStoreEnoughBytes($path, $bytesToStore)
32 {
33 // Early bail: Disabled by filter
34 if (apply_filters('wpstg.filesystem.disableDiskFreeSpaceCheck', false)) {
35 throw new \RuntimeException();
36 }
37
38 // Early bail: disk_free_space might have been disabled using php.ini "disable_functions"
39 if (!function_exists('disk_free_space')) {
40 throw new \RuntimeException('The disk_free_space function is not available.');
41 }
42
43 $path = untrailingslashit($path);
44
45 clearstatcache();
46 if (!file_exists($path)) {
47 throw new \RuntimeException('The given path does not exist.');
48 }
49
50 if (is_link($path)) {
51 throw new \RuntimeException('The given path must be a directory.');
52 }
53
54 if (!is_dir($path)) {
55 throw new \RuntimeException('The path must be a directory.');
56 }
57
58 $freeSpaceInBytes = @disk_free_space($path);
59
60 if ($freeSpaceInBytes === false) {
61 $message = '';
62 $error = error_get_last();
63
64 if (is_array($error) && array_key_exists('message', $error)) {
65 $message = $error['message'];
66 }
67
68 throw new \RuntimeException($message);
69 }
70
71 if (!is_numeric($freeSpaceInBytes)) {
72 throw new \RuntimeException('disk_free_space returned an unexpected result');
73 }
74
75 if ($freeSpaceInBytes - $bytesToStore < 0) {
76 throw DiskNotWritableException::willExceedFreeDiskSpace(abs($freeSpaceInBytes - $bytesToStore));
77 }
78 }
79
80 /**
81 * @throws DiskNotWritableException If a previous disk write test has failed.
82 */
83 public function hasDiskWriteTestFailed()
84 {
85 if (get_option(self::OPTION_DISK_WRITABLE_FAILED) === 'fail') {
86 throw DiskNotWritableException::diskNotWritable();
87 }
88 }
89
90 /**
91 * @return bool
92 * @throws DiskNotWritableException
93 * @throws FilesystemExceptions
94 */
95 public function testDiskIsWriteable()
96 {
97 $destination = $this->directory->getPluginUploadsDirectory() . '.wpstgDiskWriteCheck';
98
99 if (file_exists($destination)) {
100 unlink($destination);
101 }
102
103 // Early bail: Disk writeable check pass
104 if (@file_put_contents($destination, $this->reservedMemory)) {
105 unlink($destination);
106
107 delete_option(self::OPTION_DISK_WRITABLE_FAILED);
108
109 return true;
110 }
111
112 // First try, this might fail as the disk is full.
113 $result = $this->setLowLevelDiskFullFlag();
114
115 $this->filesystem->delete($this->directory->getCacheDirectory());
116
117 // Second try, this might succeed if the first failed as we freed up a few kb of data.
118 if (!$result) {
119 $result = $this->setLowLevelDiskFullFlag();
120 }
121
122 $this->filesystem->delete($this->directory->getTmpDirectory());
123
124 // Third try, this should succeed if the second failed, but it's the tmp directory can be very big and the request might timeout before getting here.
125 if (!$result) {
126 $result = $this->setLowLevelDiskFullFlag();
127
128 if (!$result) {
129 \WPStaging\functions\debug_log('WP STAGING DiskWriteCheck failed and could not update the option in the database.');
130 }
131 }
132
133 throw DiskNotWritableException::diskNotWritable();
134 }
135
136 protected function setLowLevelDiskFullFlag()
137 {
138 global $wpdb;
139
140 return $wpdb->query($wpdb->prepare("INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", self::OPTION_DISK_WRITABLE_FAILED, 'fail', 'no'));
141 }
142 }
143