Files
html/api/patch-l99-sse.php
Opus ec2b7be5ed
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync-2225
2026-04-23 22:25:02 +02:00

108 lines
3.9 KiB
PHP
Executable File

<?php
// Patch l99-chat.php avec pattern SSE mémoire
// Doctrine 146 : SSE memory via curl WRITEFUNCTION hook + shutdown
// Non-invasif : intercepte les chunks, save à la fin
header('Content-Type: application/json');
$target = '/var/www/html/api/l99-chat.php';
$backup = '/var/www/html/vault-gold/opus/l99-chat-doctrine146-' . date('Ymd-His') . '.bak';
if (!file_exists($target)) { echo json_encode(['ok'=>false,'err'=>'not found']); exit; }
// Check chattr
$attr = shell_exec("lsattr $target 2>&1");
if (strpos($attr, '----i') !== false) {
shell_exec("sudo chattr -i $target 2>/dev/null");
}
@mkdir(dirname($backup), 0755, true);
copy($target, $backup);
$content = file_get_contents($target);
if (strpos($content, 'DOCTRINE-146-SSE') !== false) {
echo json_encode(['ok'=>false, 'err'=>'already patched']);
exit;
}
// Injection 1 : après auth check ($q parsing), avant $env load
// Cherche: "if(!$q){echo"
$anchor1 = '$env=[];';
$inject1 = '// === DOCTRINE-146-SSE · memory bridge SSE pattern ===
if (@file_exists(__DIR__.\'/wevia-memory-bridge.php\')) { @require_once __DIR__.\'/wevia-memory-bridge.php\'; }
$__chat_id = \'l99-chat\';
$__user_id = $_GET[\'user_id\'] ?? $_COOKIE[\'weval_chat_session\'] ?? (\'anon-\'.substr(md5(($_SERVER[\'REMOTE_ADDR\']??\'\').($_SERVER[\'HTTP_USER_AGENT\']??\'\')),0,12));
$__sse_accumulator = \'\';
register_shutdown_function(function() use (&$__sse_accumulator, $__chat_id, $__user_id, $q) {
if (!function_exists(\'wevia_mem_save\')) return;
// Parse SSE chunks - extract content from data: lines
$parsed = \'\';
foreach (explode("\n", $__sse_accumulator) as $line) {
if (strpos($line, \'data: \') !== 0) continue;
$json = substr($line, 6);
if ($json === \'[DONE]\') continue;
$d = @json_decode($json, true);
// OpenAI style
if (isset($d[\'choices\'][0][\'delta\'][\'content\'])) {
$parsed .= $d[\'choices\'][0][\'delta\'][\'content\'];
}
// Custom style {t: ...}
elseif (isset($d[\'t\']) && is_string($d[\'t\'])) {
$parsed .= $d[\'t\'];
}
}
if ($parsed && $q) {
@wevia_mem_save($__chat_id, $__user_id, $q, substr($parsed, 0, 4000), \'internal\');
}
});
// === /DOCTRINE-146-SSE ===
' . $anchor1;
if (strpos($content, $anchor1) === false) {
shell_exec("sudo chattr +i $target 2>/dev/null");
echo json_encode(['ok'=>false, 'err'=>'anchor1 not found']);
exit;
}
$content = str_replace($anchor1, $inject1, $content);
// Injection 2 : hook CURLOPT_WRITEFUNCTION pour accumuler
// Cherche: "CURLOPT_WRITEFUNCTION=>function($c,$d)use($p){"
$anchor2 = 'CURLOPT_WRITEFUNCTION=>function($c,$d)use($p){';
$inject2 = 'CURLOPT_WRITEFUNCTION=>function($c,$d)use($p,&$GLOBALS){
$GLOBALS[\'__sse_accumulator\'] = ($GLOBALS[\'__sse_accumulator\'] ?? \'\') . $d;';
if (strpos($content, $anchor2) === false) {
// Try relaxed version
$relax_match = preg_match('/CURLOPT_WRITEFUNCTION\s*=>\s*function\s*\(\s*\$c\s*,\s*\$d\s*\)\s*use\s*\(\s*\$p\s*\)\s*\{/', $content);
shell_exec("sudo chattr +i $target 2>/dev/null");
echo json_encode(['ok'=>false, 'err'=>'anchor2 not found', 'relax_match'=>$relax_match]);
exit;
}
$content = str_replace($anchor2, $inject2, $content);
// Lint
$tmp = tempnam('/tmp', 'l99-sse-');
file_put_contents($tmp, $content);
$lint = shell_exec("php -l $tmp 2>&1");
if (strpos($lint, 'No syntax errors') === false) {
unlink($tmp);
shell_exec("sudo chattr +i $target 2>/dev/null");
echo json_encode(['ok'=>false, 'err'=>'lint fail', 'lint'=>$lint]);
exit;
}
file_put_contents($target, $content);
shell_exec("sudo chown www-data:www-data $target");
shell_exec("sudo chattr +i $target 2>/dev/null");
unlink($tmp);
@opcache_reset();
echo json_encode([
'ok' => true,
'backup' => $backup,
'patches' => ['shutdown_function', 'writefunction_hook'],
'ts' => date('c')
]);