| @@ -205,9 +205,9 @@ | ||
| 205 | 205 | |
| 206 | 206 | /** |
| 207 | 207 | * WordPress filesystem for use. |
| 208 | 208 | * |
| 209 | - * @return object | |
| 209 | + * @return object|null | |
| 210 | 210 | */ |
| 211 | 211 | private function wp_filesystem() |
| 212 | 212 | { |
| 213 | 213 | global $wp_filesystem; |
| @@ -220,8 +220,21 @@ | ||
| 220 | 220 | return $wp_filesystem; |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | /** |
| 224 | + * WordPress filesystem, only when it writes to local disk directly. | |
| 225 | + * An FTP/SSH transport that could not connect fatals on first use. | |
| 226 | + * | |
| 227 | + * @return object|null | |
| 228 | + */ | |
| 229 | + private function direct_filesystem() | |
| 230 | + { | |
| 231 | + $fs = $this->wp_filesystem(); | |
| 232 | + | |
| 233 | + return ($fs && isset($fs->method) && 'direct' === $fs->method) ? $fs : null; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 224 | 237 | * Get error log file location. |
| 225 | 238 | * |
| 226 | 239 | * @return string |
| 227 | 240 | */ |
| @@ -254,19 +267,8 @@ | ||
| 254 | 267 | return $log_file; |
| 255 | 268 | } |
| 256 | 269 | |
| 257 | 270 | /** |
| 258 | - * Clear the log. | |
| 259 | - * @return void | |
| 260 | - */ | |
| 261 | - public static function clear() | |
| 262 | - { | |
| 263 | - if (ini_get('error_log') === '') return; | |
| 264 | - $handle = fopen(ini_get('error_log'), 'w'); | |
| 265 | - fclose($handle); | |
| 266 | - } | |
| 267 | - | |
| 268 | - /** | |
| 269 | 271 | * Get human read number of units. |
| 270 | 272 | * |
| 271 | 273 | * @param int $bytes |
| 272 | 274 | * @return string |
| @@ -297,38 +299,28 @@ | ||
| 297 | 299 | * @return string|false Log file path or false on failure |
| 298 | 300 | */ |
| 299 | 301 | public function createErrorLog() |
| 300 | 302 | { |
| 301 | - // Use the same directory as Log_Manager for consistency | |
| 302 | - $log_directory = WP_CONTENT_DIR . '/metasync_data'; | |
| 303 | - | |
| 304 | - // Create directory if it doesn't exist | |
| 305 | - if (!is_dir($log_directory)) { | |
| 306 | - if (!@mkdir($log_directory, 0755, true)) { | |
| 307 | - error_log('Metasync_Error_Logs: Failed to create log directory: ' . $log_directory); | |
| 308 | - return false; | |
| 309 | - } | |
| 303 | + // Directory creation, web-server protection, and writability | |
| 304 | + // guarantees live in Metasync_Data_Store so every writer agrees on | |
| 305 | + // the location; a false return means "no writable data directory". | |
| 306 | + if (false === Metasync_Data_Store::base_dir()) { | |
| 307 | + return false; | |
| 310 | 308 | } |
| 311 | 309 | |
| 312 | - // Verify directory is writable | |
| 313 | - if (!is_writable($log_directory)) { | |
| 314 | - @chmod($log_directory, 0755); | |
| 315 | - if (!is_writable($log_directory)) { | |
| 316 | - error_log('Metasync_Error_Logs: Directory not writable: ' . $log_directory); | |
| 317 | - return false; | |
| 318 | - } | |
| 310 | + // Point to the actual log file being written by Log_Manager | |
| 311 | + $log_file = Metasync_Data_Store::file_path('plugin_errors.log'); | |
| 312 | + if (false === $log_file) { | |
| 313 | + return false; | |
| 319 | 314 | } |
| 320 | 315 | |
| 321 | - // Point to the actual log file being written by Log_Manager | |
| 322 | - $log_file = wp_normalize_path($log_directory . '/plugin_errors.log'); | |
| 323 | - | |
| 324 | 316 | // Create file if it doesn't exist |
| 325 | 317 | if (!file_exists($log_file)) { |
| 326 | - if (@file_put_contents($log_file, '') === false) { | |
| 327 | - error_log('Metasync_Error_Logs: Failed to create log file: ' . $log_file); | |
| 318 | + $fs = $this->direct_filesystem(); | |
| 319 | + if (!$fs || !$fs->put_contents($log_file, '', defined('FS_CHMOD_FILE') ? FS_CHMOD_FILE : 0644)) { | |
| 320 | + error_log('Metasync_Error_Logs: Failed to create log file: ' . $log_file); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets | |
| 328 | 321 | return false; |
| 329 | 322 | } |
| 330 | - @chmod($log_file, 0644); | |
| 331 | 323 | } |
| 332 | 324 | |
| 333 | 325 | // Rotate log file if it's too large |
| 334 | 326 | $this->rotate_log_if_needed($log_file); |
| @@ -356,12 +348,12 @@ | ||
| 356 | 348 | return false; |
| 357 | 349 | } |
| 358 | 350 | |
| 359 | 351 | // Create backup of current log with timestamp |
| 360 | - $backup_file = $log_file . '.old.' . date('Y-m-d-His'); | |
| 352 | + $backup_file = $log_file . '.old.' . gmdate('Y-m-d-His'); | |
| 361 | 353 | |
| 362 | 354 | // Read last 50% of the file to keep recent entries |
| 363 | - $wp_filesystem = $this->wp_filesystem(); | |
| 355 | + $wp_filesystem = $this->direct_filesystem(); | |
| 364 | 356 | if (!$wp_filesystem) { |
| 365 | 357 | return false; |
| 366 | 358 | } |
| 367 | 359 | |
| @@ -378,10 +370,9 @@ | ||
| 378 | 370 | // Keep the most recent lines |
| 379 | 371 | $recent_content = implode("\n", array_slice($lines, -$keep_lines)); |
| 380 | 372 | |
| 381 | 373 | // Archive old content |
| 382 | - @file_put_contents($backup_file, $content); | |
| 383 | - @chmod($backup_file, 0644); | |
| 374 | + $wp_filesystem->put_contents($backup_file, $content, FS_CHMOD_FILE); | |
| 384 | 375 | |
| 385 | 376 | // Write recent content back to main log |
| 386 | 377 | $wp_filesystem->put_contents($log_file, $recent_content, FS_CHMOD_FILE); |
| 387 | 378 | |
| @@ -412,8 +403,8 @@ | ||
| 412 | 403 | |
| 413 | 404 | // Delete all but the 3 newest |
| 414 | 405 | $files_to_delete = array_slice($backup_files, 3); |
| 415 | 406 | foreach ($files_to_delete as $file) { |
| 416 | - @unlink($file); | |
| 407 | + @wp_delete_file($file); | |
| 417 | 408 | } |
| 418 | 409 | } |
| 419 | 410 | } |