-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsync.php
More file actions
111 lines (98 loc) · 4.33 KB
/
Copy pathsync.php
File metadata and controls
111 lines (98 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?php
ob_start(); // Indispensable : permet aux handlers d'erreur de nettoyer la sortie avant d'envoyer du JSON
set_error_handler(function(int $errno, string $errstr, string $errfile, int $errline): bool {
if (!(error_reporting() & $errno)) return false;
if (ob_get_level() > 0) ob_clean();
error_log("[sync] Erreur PHP [$errno] : $errstr ($errfile:$errline)");
header('Content-Type: application/json');
http_response_code(500);
echo json_encode(['ok' => false, 'msg' => "Erreur interne du serveur."]);
exit;
});
set_exception_handler(function(Throwable $e): void {
if (ob_get_level() > 0) ob_clean();
error_log("[sync] Exception : " . $e->getMessage() . " ({$e->getFile()}:{$e->getLine()})");
header('Content-Type: application/json');
http_response_code(500);
echo json_encode(['ok' => false, 'msg' => "Erreur interne du serveur."]);
exit;
});
require 'config.php';
require 'auth.php';
requireLogin(); // Requête AJAX : retourne JSON 401 si session expirée
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
if (ob_get_level() > 0) ob_clean();
header('Content-Type: application/json');
http_response_code(405);
echo json_encode(['ok' => false, 'msg' => t('sync.err_method')]);
exit;
}
csrfVerify();
if (!function_exists('exec')) {
if (ob_get_level() > 0) ob_clean();
header('Content-Type: application/json');
http_response_code(500);
echo json_encode(['ok' => false, 'msg' => t('sync.err_exec')]);
exit;
}
$pyScript = __DIR__ . '/sync_calls.py';
if (!is_file($pyScript) || !is_readable($pyScript)) {
if (ob_get_level() > 0) ob_clean();
error_log("[sync] Script Python introuvable : $pyScript");
header('Content-Type: application/json');
http_response_code(500);
echo json_encode(['ok' => false, 'msg' => t('sync.err_script')]);
exit;
}
// ── Lecture de PYTHON_EXE depuis le fichier .env ──────────────────────────────
$envPath = '/path/to/journal.env';
$pythonExe = PHP_OS_FAMILY === 'Windows' ? 'python' : 'python3';
if (is_readable($envPath)) {
foreach (file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
if ($line === '' || $line[0] === '#') continue;
[$k, $v] = array_pad(explode('=', $line, 2), 2, '');
if (trim($k) === 'PYTHON_EXE') {
$candidate = trim($v, "\"'");
if ($candidate !== ''
&& !preg_match('/[;&|`$<>\n\r"\']/', $candidate)
&& is_file($candidate)
&& is_executable($candidate)) {
$pythonExe = $candidate;
} else {
error_log("[sync] PYTHON_EXE invalide ignoré : $candidate");
}
break;
}
}
}
// ── Verrou pour éviter les synchronisations concurrentes ──────────────────────
// Deux utilisateurs cliquant simultanément pourraient corrompre la DB ou le CSV distant.
$lockFile = __DIR__ . '/sync.lock';
$lockFp = fopen($lockFile, 'c');
if ($lockFp === false || !flock($lockFp, LOCK_EX | LOCK_NB)) {
if ($lockFp) fclose($lockFp);
if (ob_get_level() > 0) ob_clean();
header('Content-Type: application/json');
echo json_encode(['ok' => false, 'msg' => t('sync.err_busy')]);
exit;
}
// ── Exécution du script Python ────────────────────────────────────────────────
$prefix = PHP_OS_FAMILY === 'Windows' ? 'set PYTHONIOENCODING=utf-8 && ' : '';
$cmd = $prefix . escapeshellarg($pythonExe) . ' ' . escapeshellarg($pyScript) . ' 2>&1';
$output = [];
$code = 0;
exec($cmd, $output, $code);
// Libération du verrou dès que exec() est terminé
flock($lockFp, LOCK_UN);
fclose($lockFp);
if (ob_get_level() > 0) ob_clean();
header('Content-Type: application/json');
if ($code === 0) {
// Première ligne de stdout Python : résultat métier ("OK: 3 nouvel(aux) appel(s)" ou "Journal à jour")
$msg = trim($output[0] ?? '') ?: t('sync.done');
} else {
// Erreur : on journalise le détail côté serveur, on retourne un message générique
error_log('[sync_calls] code=' . $code . ' : ' . implode(' | ', array_slice($output, 0, 10)));
$msg = t('sync.err_code', ['code' => $code]);
}
echo json_encode(['ok' => ($code === 0), 'msg' => $msg]);