140 lines
5.7 KiB
PHP
Executable File
140 lines
5.7 KiB
PHP
Executable File
<?php
|
|
// Patch 2 chatbots : weval-chatbot-api.php + openclaw-proxy.php
|
|
// Pattern ob_start + register_shutdown_function (non-invasif, capture JSON output)
|
|
// Doctrine 141 application
|
|
header('Content-Type: application/json');
|
|
|
|
function patch_chatbot(string $file, string $chat_id): array {
|
|
if (!file_exists($file)) return ['ok'=>false, 'err'=>'not found', 'file'=>$file];
|
|
|
|
$content = file_get_contents($file);
|
|
|
|
// Skip si deja patched
|
|
if (strpos($content, 'DOCTRINE-141-SHUTDOWN') !== false) {
|
|
return ['ok'=>false, 'err'=>'already patched', 'file'=>$file];
|
|
}
|
|
|
|
// Backup
|
|
$backup = '/var/www/html/vault-gold/opus/' . basename($file) . '.doctrine141-' . date('Ymd-His') . '.bak';
|
|
@mkdir(dirname($backup), 0755, true);
|
|
copy($file, $backup);
|
|
|
|
// Injection APRES le premier header(...) ou require (avant les die/echo)
|
|
// Trouver la première ligne après les includes/headers/require
|
|
|
|
// Pattern d'injection : on cherche la première ligne avec $input ou $msg = ou $lo =
|
|
$inject = "\n// === DOCTRINE-141-SHUTDOWN · memory bridge ===
|
|
if (@file_exists(__DIR__.'/wevia-memory-bridge.php')) { @require_once __DIR__.'/wevia-memory-bridge.php'; }
|
|
\$__chat_id = '" . $chat_id . "';
|
|
\$__user_id = \$_COOKIE['weval_chat_session'] ?? (\$_SERVER['HTTP_X_USER_ID'] ?? ('anon-'.substr(md5((\$_SERVER['REMOTE_ADDR']??'').(\$_SERVER['HTTP_USER_AGENT']??'')),0,12)));
|
|
\$__msg_for_mem = '';
|
|
register_shutdown_function(function() use (&\$__msg_for_mem, \$__chat_id, \$__user_id) {
|
|
if (!function_exists('wevia_mem_save')) return;
|
|
\$out = ob_get_contents();
|
|
if (!\$out) return;
|
|
\$d = @json_decode(\$out, true);
|
|
\$resp = is_array(\$d) ? (\$d['response'] ?? \$d['answer'] ?? \$d['content'] ?? '') : \$out;
|
|
if (\$resp && \$__msg_for_mem) {
|
|
@wevia_mem_save(\$__chat_id, \$__user_id, \$__msg_for_mem, is_string(\$resp)?\$resp:json_encode(\$resp), 'internal');
|
|
}
|
|
});
|
|
ob_start();
|
|
// === /DOCTRINE-141-SHUTDOWN ===
|
|
\n";
|
|
|
|
// Insertion : après la dernière header() ou require() initiale, avant la logique
|
|
// On cherche la ligne la plus safe : après '$input = json_decode' ou '$msg = '
|
|
$anchors = [
|
|
'$input = json_decode(file_get_contents("php://input"), true) ?: [];',
|
|
'$input = @json_decode(file_get_contents("php://input"), true) ?: [];',
|
|
'$raw = @file_get_contents("php://input");'
|
|
];
|
|
|
|
$injected = false;
|
|
foreach ($anchors as $anchor) {
|
|
$pos = strpos($content, $anchor);
|
|
if ($pos !== false) {
|
|
// Insertion juste après la ligne de l'anchor (aprs le ;)
|
|
$end = strpos($content, "\n", $pos) + 1;
|
|
$before = substr($content, 0, $end);
|
|
$after = substr($content, $end);
|
|
$content = $before . $inject . $after;
|
|
$injected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$injected) {
|
|
return ['ok'=>false, 'err'=>'anchor not found', 'file'=>$file];
|
|
}
|
|
|
|
// Ajouter la capture du msg juste après sa définition
|
|
$msg_captures = [
|
|
['old' => '$msg = $input["message"] ?? $_GET["message"] ?? "";',
|
|
'new' => '$msg = $input["message"] ?? $_GET["message"] ?? ""; $__msg_for_mem = $msg;'],
|
|
['old' => '$msg = trim($in["message"] ?? "");',
|
|
'new' => '$msg = trim($in["message"] ?? ""); $__msg_for_mem = $msg;'],
|
|
['old' => '$message = trim($input[\'message\'] ?? \'\');',
|
|
'new' => '$message = trim($input[\'message\'] ?? \'\'); $__msg_for_mem = $message;'],
|
|
['old' => "\$msg = trim(\$input['message'] ?? '');",
|
|
'new' => "\$msg = trim(\$input['message'] ?? ''); \$__msg_for_mem = \$msg;"]
|
|
];
|
|
|
|
foreach ($msg_captures as $cap) {
|
|
if (strpos($content, $cap['old']) !== false) {
|
|
$content = str_replace($cap['old'], $cap['new'], $content);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Lint
|
|
$tmp = tempnam('/tmp', 'cbpatch-');
|
|
file_put_contents($tmp, $content);
|
|
$lint = shell_exec("php -l $tmp 2>&1");
|
|
if (strpos($lint, 'No syntax errors') === false) {
|
|
unlink($tmp);
|
|
return ['ok'=>false, 'err'=>'php lint fail', 'lint'=>$lint, 'file'=>$file];
|
|
}
|
|
|
|
// Write
|
|
shell_exec("sudo chattr -i $file 2>/dev/null");
|
|
file_put_contents($file, $content);
|
|
shell_exec("sudo chown www-data:www-data $file");
|
|
shell_exec("sudo chattr +i $file 2>/dev/null");
|
|
unlink($tmp);
|
|
|
|
return ['ok'=>true, 'file'=>$file, 'backup'=>$backup, 'chat_id'=>$chat_id];
|
|
}
|
|
|
|
// Apply to 2 chatbots
|
|
$results = [
|
|
'weval-chatbot-api' => patch_chatbot('/var/www/html/api/weval-chatbot-api.php', 'weval-chatbot'),
|
|
'openclaw-proxy' => patch_chatbot('/var/www/html/api/openclaw-proxy.php', 'openclaw-proxy'),
|
|
];
|
|
|
|
@opcache_reset();
|
|
|
|
// Tests
|
|
foreach (['weval-chatbot-api', 'openclaw-proxy'] as $name) {
|
|
if (($results[$name]['ok'] ?? false)) {
|
|
$sess_cookie = 'opus-phase4-' . $name;
|
|
$test = shell_exec("curl -sk -m 8 -H 'X-User-Id: $sess_cookie' 'http://localhost/api/$name.php' -H 'Content-Type: application/json' -d '{\"message\":\"hello test phase4\"}' 2>&1 | head -c 300");
|
|
$results[$name]['test_response'] = substr(trim($test), 0, 250);
|
|
}
|
|
}
|
|
|
|
// Verify Redis
|
|
if (file_exists('/var/www/html/api/wevia-memory-bridge.php')) {
|
|
require_once '/var/www/html/api/wevia-memory-bridge.php';
|
|
$mem_stats = [
|
|
'weval-chatbot' => wevia_mem_load('weval-chatbot', 'opus-phase4-weval-chatbot-api', 5),
|
|
'openclaw-proxy' => wevia_mem_load('openclaw-proxy', 'opus-phase4-openclaw-proxy', 5),
|
|
];
|
|
$results['_memory_check'] = [
|
|
'weval-chatbot_msgs' => count($mem_stats['weval-chatbot']),
|
|
'openclaw-proxy_msgs' => count($mem_stats['openclaw-proxy']),
|
|
];
|
|
}
|
|
|
|
echo json_encode($results, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|