PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / trunk
JetBackup – Backup, Restore & Migrate vtrunk
3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / 3rdparty / SleekDB / Classes / IoHelper.php
backup / src / JetBackup / 3rdparty / SleekDB / Classes Last commit date
.htaccess 1 year ago CacheHandler.php 1 year ago ConditionsHandler.php 1 year ago DocumentFinder.php 1 year ago DocumentReducer.php 1 year ago DocumentUpdater.php 4 months ago IoHelper.php 4 months ago NestedHelper.php 1 year ago index.html 1 year ago web.config 1 year ago
IoHelper.php
308 lines
1 <?php
2
3 namespace SleekDB\Classes;
4
5 use Closure;
6 use Exception;
7 use FilesystemIterator;
8 use JetBackup\Filesystem\AtomicWrite;
9 use RecursiveDirectoryIterator;
10 use RecursiveIteratorIterator;
11 use SleekDB\Exceptions\IOException;
12 use SleekDB\Exceptions\JsonException;
13
14 /**
15 * Class IoHelper
16 * Helper to handle file input/ output.
17 */
18 class IoHelper {
19
20 /**
21 * @param string $path
22 * @throws IOException
23 */
24 public static function checkWrite(string $path) {
25 if (file_exists($path) === false) $path = dirname($path);
26 if (!is_writable($path)) throw new IOException( "Directory or file is not writable at \"$path\". Please change permission." );
27 }
28
29 /**
30 * @param string $path
31 * @throws IOException
32 */
33 public static function checkRead(string $path) {
34 if (!is_readable($path)) throw new IOException( "Directory or file is not readable at \"$path\". Please change permission." );
35 }
36
37 /**
38 * @param $name
39 *
40 * @return bool
41 */
42 public static function skipFile($name): bool {
43
44 $skipList = array(
45 '.',
46 '..',
47 '.htaccess',
48 'index.html',
49 'web.config'
50 );
51
52 return in_array($name, $skipList);
53 }
54
55
56 /**
57 * @throws IOException
58 */
59 public static function getFileContentRaw(string $filePath): string {
60
61 self::checkRead($filePath);
62 if (!file_exists($filePath)) throw new IOException("File does not exist: $filePath");
63
64 $content = false;
65 $fp = fopen($filePath, 'rb');
66 if (flock($fp, LOCK_SH)) $content = stream_get_contents($fp);
67 flock($fp, LOCK_UN);
68 fclose($fp);
69
70 if ($content === false) throw new IOException("Could not retrieve the content of a file. Please check permissions at: $filePath");
71 return $content;
72 }
73
74
75 /**
76 * @param string $filePath
77 * @return string
78 * @throws IOException
79 */
80 public static function getFileContent(string $filePath): string {
81
82 try {
83
84 self::checkRead($filePath);
85 if (!file_exists($filePath)) throw new IOException("File does not exist: $filePath");
86
87 $content = false;
88 $fp = @fopen($filePath, 'rb');
89 if (flock($fp, LOCK_SH)) $content = stream_get_contents($fp);
90 flock($fp, LOCK_UN);
91 fclose($fp);
92
93 if ($content === false) throw new IOException("Could not retrieve the content of a file. Please check permissions at: $filePath");
94 $_swap_content = self::checkSwap($filePath);
95 $_valid_json = self::validateJson($content);
96
97 if ($_swap_content && !$_valid_json) {
98 AtomicWrite::write($filePath, $_swap_content, null);
99 return $_swap_content;
100 }
101
102 return $content;
103
104 } catch (Exception $e) {
105 throw new IOException($e->getMessage(), $e->getCode());
106 }
107
108 }
109
110
111 public static function isSwapFile($file): bool {
112
113 $ending = '.swap';
114 $endingLength = strlen($ending);
115 if ($endingLength > strlen($file)) return false;
116 $fileEnding = substr($file, -$endingLength);
117 return $fileEnding === $ending;
118
119 }
120
121 public static function validateJson($json): bool {
122 json_decode($json);
123 return (json_last_error() == JSON_ERROR_NONE);
124 }
125
126 public static function checkSwap($path) {
127
128 $_swap_file = $path . '.swap';
129
130 if (file_exists($_swap_file)) {
131 $_swap_contents = @file_get_contents($_swap_file);
132 if (self::validateJson($_swap_contents)) {
133 // Ensure valid JSON before proceeding
134 if (file_exists($path)) {
135 @unlink($_swap_file);
136 return $_swap_contents;
137 }
138 } else {
139 // Handle invalid JSON in swap file, clean up
140 @unlink($_swap_file);
141 }
142 }
143
144 return null;
145 }
146
147
148 /**
149 * @param string $filePath
150 * @param string $content
151 * @throws IOException
152 */
153 public static function writeContentToFile(string $filePath, string $content) {
154 try {
155 self::checkWrite($filePath);
156 AtomicWrite::write($filePath, $content, null);
157 } catch (Exception $e) {
158 throw new IOException($e->getMessage(), $e->getCode());
159 }
160 }
161
162
163
164 /**
165 * @param string $folderPath
166 * @return bool
167 * @throws IOException
168 */
169 public static function deleteFolder(string $folderPath): bool {
170 self::checkWrite($folderPath);
171 $it = new RecursiveDirectoryIterator($folderPath, FilesystemIterator::SKIP_DOTS);
172 $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
173 foreach ($files as $file) {
174 self::checkWrite($file);
175 if ($file->isDir()) {
176 rmdir($file->getRealPath());
177 } else {
178 unlink($file->getRealPath());
179 }
180 }
181 return rmdir($folderPath);
182 }
183
184 /**
185 * @param string $folderPath
186 * @param int $chmod
187 * @throws IOException
188 */
189 public static function createFolder(string $folderPath, int $chmod){
190 if (file_exists($folderPath) === true) return;
191 self::checkWrite($folderPath);
192 if (!file_exists($folderPath) && !mkdir($folderPath, $chmod, true) && !is_dir($folderPath)) {
193 throw new IOException(
194 'Unable to create the a directory at ' . $folderPath
195 );
196 }
197 }
198
199 /**
200 * @param string $filePath
201 * @param Closure $updateContentFunction Has to return a string or an array that will be encoded to json.
202 *
203 * @return string
204 * @throws IOException
205 * @throws JsonException*@throws Exception
206 */
207 public static function updateFileContent(string $filePath, Closure $updateContentFunction): string {
208
209 self::checkRead($filePath);
210 self::checkWrite($filePath);
211
212 $content = false;
213
214 $fp = fopen($filePath, 'rb');
215 if (flock($fp, LOCK_SH)) $content = stream_get_contents($fp);
216 flock($fp, LOCK_UN);
217 fclose($fp);
218 if ($content === false) throw new IOException("Could not get shared lock for file: $filePath");
219
220 $_swap_content = self::checkSwap($filePath);
221 $_valid_json = self::validateJson($content);
222 if ($_swap_content && !$_valid_json) return $_swap_content;
223
224 $content = $updateContentFunction($content);
225
226 if (!is_string($content)) {
227 $encodedContent = json_encode($content, JSON_INVALID_UTF8_SUBSTITUTE);
228 if ($encodedContent === false) {
229 $content = (!is_object($content) && !is_array($content) && !is_null($content)) ? $content : gettype($content);
230 throw new JsonException("Could not encode content with json_encode. Content: \"$content\".");
231 }
232 $content = $encodedContent;
233 }
234
235 AtomicWrite::write($filePath, $content, null);
236
237 return $content;
238 }
239
240 /**
241 * @param string $filePath
242 * @return bool
243 */
244 public static function deleteFile(string $filePath): bool {
245
246 if (false === file_exists($filePath)) return true;
247
248 try {
249 self::checkWrite($filePath);
250 } catch (Exception $exception) {
251 return false;
252 }
253
254 return (@unlink($filePath) && !file_exists($filePath));
255 }
256
257 /**
258 * @param array $filePaths
259 * @return bool
260 */
261 public static function deleteFiles(array $filePaths): bool
262 {
263 foreach ($filePaths as $filePath) {
264 // if a file does not exist, we do not need to delete it.
265 if (true === file_exists($filePath)) {
266 try {
267 self::checkWrite($filePath);
268 if (false === @unlink($filePath) || file_exists($filePath)) return false;
269 } catch (Exception $exception) {
270 // TODO trigger a warning or exception
271 return false;
272 }
273 }
274 }
275 return true;
276 }
277
278 /**
279 * Strip string for secure file access.
280 * @param string $string
281 * @return string
282 */
283 public static function secureStringForFileAccess(string $string): string {
284 return (str_replace(array(".", "/", "\\"), "", $string));
285 }
286
287 /**
288 * Appends a slash ("/") to the given directory path if there is none.
289 * @param string $directory
290 */
291 public static function normalizeDirectory(string &$directory) {
292 if (!empty($directory) && substr($directory, -1) !== DIRECTORY_SEPARATOR) {
293 $directory .= DIRECTORY_SEPARATOR;
294 }
295 }
296
297 /**
298 * Returns the amount of files in folder.
299 * @param string $folder
300 * @return int
301 * @throws IOException
302 */
303 public static function countFolderContent(string $folder): int {
304 self::checkRead($folder);
305 $fi = new \FilesystemIterator($folder, \FilesystemIterator::SKIP_DOTS);
306 return iterator_count($fi);
307 }
308 }