PluginProbe
Media Cloud Sync / 1.4.1
Media Cloud Sync v1.4.1
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
← All changes | includes/base/logger.php +110 -44 1.3.101.4.1 View file →
@@ -6,8 +6,9 @@
6 6 class Logger {
7 7 private static $instance = null;
8 8 private $log_dir;
9 9 private $log_file;
10 + private $handle = null;
10 11
11 12 private function __construct() {
12 13 $upload_dir = wp_upload_dir();
13 14 $this->log_dir = trailingslashit($upload_dir['basedir']) . Schema::getConstant('UPLOADS');
@@ -18,8 +19,14 @@
18 19
19 20 $this->log_file = $this->log_dir . '/sync-log.json';
20 21 }
21 22
23 + public function __destruct() {
24 + if (is_resource($this->handle)) {
25 + fclose($this->handle);
26 + }
27 + }
28 +
22 29 /**
23 30 * Singleton instance
24 31 */
25 32 public static function instance() {
@@ -29,8 +36,71 @@
29 36 return self::$instance;
30 37 }
31 38
32 39 /**
40 + * Reuse a single open file handle for the process instead of
41 + * reopening/closing on every call (heavy when many logs happen at once)
42 + */
43 + private function get_handle($create = true) {
44 + if (is_resource($this->handle)) {
45 + return $this->handle;
46 + }
47 +
48 + if (!$create && !file_exists($this->log_file)) {
49 + return null;
50 + }
51 +
52 + $this->handle = fopen($this->log_file, 'c+');
53 + return $this->handle ?: null;
54 + }
55 +
56 + /**
57 + * Read logs under a shared lock
58 + */
59 + private function read_logs() {
60 + $handle = $this->get_handle(false);
61 + if (!$handle) return [];
62 +
63 + $logs = [];
64 + try {
65 + if (flock($handle, LOCK_SH)) {
66 + rewind($handle);
67 + $content = stream_get_contents($handle);
68 + $logs = json_decode($content, true) ?: [];
69 + }
70 + } finally {
71 + flock($handle, LOCK_UN);
72 + }
73 +
74 + return $logs;
75 + }
76 +
77 + /**
78 + * Read-modify-write logs under an exclusive lock held for the whole cycle
79 + */
80 + private function update_logs(callable $mutator) {
81 + $handle = $this->get_handle(true);
82 + if (!$handle) return;
83 +
84 + try {
85 + if (flock($handle, LOCK_EX)) {
86 + rewind($handle);
87 + $content = stream_get_contents($handle);
88 + $logs = json_decode($content, true) ?: [];
89 +
90 + $logs = $mutator($logs);
91 +
92 + rewind($handle);
93 + ftruncate($handle, 0);
94 + fwrite($handle, wp_json_encode($logs));
95 + fflush($handle);
96 + }
97 + } finally {
98 + flock($handle, LOCK_UN);
99 + }
100 + }
101 +
102 + /**
33 103 * Add or update a log entry
34 104 */
35 105 public function add_log($type, $media_id, $source_type, $log = []) {
36 106 $entry = [
@@ -46,30 +116,25 @@
46 116 /**
47 117 * Append log using file-based indexing
48 118 */
49 119 private function append_log($entry, $log=[]) {
50 - $logs = [];
120 + $this->update_logs(function($logs) use ($entry, $log) {
121 + // Unique key per media/type/source
122 + $key = $entry['media_id'] . '|' . $entry['type'] . '|' . $entry['source_type'];
51 123
52 - if (file_exists($this->log_file)) {
53 - $content = file_get_contents($this->log_file);
54 - $logs = json_decode($content, true) ?: [];
55 - }
56 -
57 - // Unique key per media/type/source
58 - $key = $entry['media_id'] . '|' . $entry['type'] . '|' . $entry['source_type'];
59 -
60 - if (isset($logs[$key])) {
61 - if (!isset($logs[$key]['logs']) || !is_array($logs[$key]['logs'])) {
62 - $logs[$key]['logs'] = [];
124 + if (isset($logs[$key])) {
125 + if (!isset($logs[$key]['logs']) || !is_array($logs[$key]['logs'])) {
126 + $logs[$key]['logs'] = [];
127 + }
128 + $logs[$key]['logs'][] = $log;
129 + $logs[$key]['time'] = $entry['time'] ?? current_time('mysql');
130 + } else {
131 + $logs[$key] = $entry;
132 + $logs[$key]['logs'][] = $log;
63 133 }
64 - $logs[$key]['logs'][] = $log;
65 - $logs[$key]['time'] = $entry['time'] ?? current_time('mysql');
66 - } else {
67 - $logs[$key] = $entry;
68 - $logs[$key]['logs'][] = $log;
69 - }
70 134
71 - file_put_contents($this->log_file, wp_json_encode($logs));
135 + return $logs;
136 + });
72 137 }
73 138
74 139 /**
75 140 * Get log by media ID, type, and source type
@@ -74,12 +139,10 @@
74 139 /**
75 140 * Get log by media ID, type, and source type
76 141 */
77 142 public function get_log($type, $media_id, $source_type) {
78 - if (!file_exists($this->log_file)) return [];
79 -
80 143 $key = $media_id . '|' . $type . '|' . $source_type;
81 - return json_decode(file_get_contents($this->log_file), true)[$key] ?? [];
144 + return $this->read_logs()[$key] ?? [];
82 145 }
83 146
84 147 /**
85 148 * Get all logs (numeric array, supports pagination)
@@ -94,9 +157,9 @@
94 157 'per_page' => $per_page ?:1,
95 158 ];
96 159 }
97 160
98 - $logs = array_values(json_decode(file_get_contents($this->log_file), true) ?: []);
161 + $logs = array_values($this->read_logs());
99 162
100 163 $total = count($logs);
101 164
102 165 if ($page === null || $per_page === null) {
@@ -135,9 +198,9 @@
135 198 'per_page' => $per_page ?:1,
136 199 ];
137 200 };
138 201
139 - $all_logs = json_decode(file_get_contents($this->log_file) ?: '[]', true) ?: [];
202 + $all_logs = $this->read_logs();
140 203
141 204 $logs = array_values(array_filter($all_logs, function($log) use ($type) {
142 205 return isset($log['type']) && $log['type'] === $type;
143 206 }));
@@ -174,17 +237,17 @@
174 237 */
175 238 public function remove_logs_by_type($type) {
176 239 if (!file_exists($this->log_file)) return;
177 240
178 - $logs = json_decode(file_get_contents($this->log_file), true) ?: [];
179 -
180 - foreach ($logs as $key => $log) {
181 - if (isset($log['type']) && $log['type'] === $type) {
182 - unset($logs[$key]);
241 + $this->update_logs(function($logs) use ($type) {
242 + foreach ($logs as $key => $log) {
243 + if (isset($log['type']) && $log['type'] === $type) {
244 + unset($logs[$key]);
245 + }
183 246 }
184 - }
185 247
186 - file_put_contents($this->log_file, wp_json_encode($logs));
248 + return $logs;
249 + });
187 250 }
188 251
189 252 /**
190 253 * Remove logs by media ID, type, and source type
@@ -191,17 +254,17 @@
191 254 */
192 255 public function remove_log($type, $media_id, $source_type) {
193 256 if (!file_exists($this->log_file)) return;
194 257
195 - $logs = json_decode(file_get_contents($this->log_file), true) ?: [];
258 + $this->update_logs(function($logs) use ($type, $media_id, $source_type) {
259 + $key = $media_id . '|' . $type . '|' . $source_type;
196 260
197 - $key = $media_id . '|' . $type . '|' . $source_type;
261 + if (isset($logs[$key])) {
262 + unset($logs[$key]);
263 + }
198 264
199 - if (isset($logs[$key])) {
200 - unset($logs[$key]);
201 - }
202 -
203 - file_put_contents($this->log_file, wp_json_encode($logs));
265 + return $logs;
266 + });
204 267 }
205 268
206 269 /**
207 270 * Remove Log by media ID & source type
@@ -208,15 +271,13 @@
208 271 */
209 272 public function remove_log_by_media_id($media_id, $source_type) {
210 273 if (!file_exists($this->log_file)) return;
211 274
212 - $logs = json_decode(file_get_contents($this->log_file), true) ?: [];
213 -
214 - $new_log = array_filter($logs, function($log) use ($media_id, $source_type) {
215 - return $log['media_id'] !== $media_id || $log['source_type'] !== $source_type;
275 + $this->update_logs(function($logs) use ($media_id, $source_type) {
276 + return array_filter($logs, function($log) use ($media_id, $source_type) {
277 + return $log['media_id'] !== $media_id || $log['source_type'] !== $source_type;
278 + });
216 279 });
217 -
218 - file_put_contents($this->log_file, wp_json_encode($new_log));
219 280 }
220 281
221 282 /**
222 283 * Clear all logs
@@ -221,9 +282,14 @@
221 282 /**
222 283 * Clear all logs
223 284 */
224 285 public function clear_logs() {
286 + if (is_resource($this->handle)) {
287 + fclose($this->handle);
288 + $this->handle = null;
289 + }
290 +
225 291 if (file_exists($this->log_file)) {
226 292 unlink($this->log_file);
227 293 }
228 294 }
229 295 }