PluginProbe
404 Solution / 4.3.0
404 Solution v4.3.0
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / php / FileSync.php

FileSync.php in 404 Solution 4.3.0, at includes/php/FileSync.php

87 lines 2.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 class ABJ_404_Solution_FileSync {
9
10 /** @var self|null */
11 private static $instance = null;
12 /**
13 * Test seam: install or clear the cached singleton instance without
14 * private-field reflection. Pass null to reset between tests; pass a
15 * configured instance (or double) to install it. Mirrors the setInstance()
16 * contract on DataAccess / PluginLogic (M105 singleton-reset seam).
17 *
18 * @param self|null $instance
19 * @return void
20 */
21 public static function setInstance($instance) {
22 self::$instance = $instance;
23 }
24
25
26 /** @return self */
27 public static function getInstance(): self {
28 if (self::$instance == null) {
29 self::$instance = new ABJ_404_Solution_FileSync();
30 }
31
32 return self::$instance;
33 }
34
35 /**
36 * @param string $key
37 * @return string
38 */
39 function getSyncFilePath(string $key): string {
40 $filePath = abj404_getUploadsDir() . 'SYNC_FILE_' . $key . '.txt';
41 return $filePath;
42 }
43
44 /**
45 * @param string $key
46 * @return string
47 */
48 function getOwnerFromFile(string $key): string {
49 $filePath = $this->getSyncFilePath($key);
50
51 // Fixed: TOCTOU race condition - catch exception instead of check-then-read
52 try {
53 $contents = ABJ_404_Solution_FileSystemService::readFileContents($filePath, false);
54 return $contents;
55 } catch (Exception $e) { // allow-silent-catch: TOCTOU-safe file read; missing or unreadable file returns empty, caller treats as "no lock owner"
56 return "";
57 }
58 }
59
60 /**
61 * @param string $key
62 * @param string $uniqueID
63 * @return void
64 */
65 function writeOwnerToFile(string $key, string $uniqueID): void {
66 $filePath = $this->getSyncFilePath($key);
67
68 // Fixed: Check return value to handle write failures (disk full, permissions, etc.)
69 $result = @file_put_contents($filePath, $uniqueID, LOCK_EX);
70
71 if ($result === false) {
72 throw new Exception("Failed to write lock file: " . $filePath);
73 }
74 }
75
76 /**
77 * @param string $uniqueID
78 * @param string $key
79 * @return void
80 */
81 function releaseLock(string $uniqueID, string $key): void {
82 $filePath = $this->getSyncFilePath($key);
83 ABJ_404_Solution_FileSystemService::safeUnlink($filePath);
84 }
85
86 }
87