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/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/includes/polana_v12_pages.php
<?php
declare(strict_types=1);
/**
 * POLANA V12 — server-rendered, reviewed translations of visible text in public static pages.
 * Do not translate blog posts/menu data here; those have their own V9 fields/workflows.
 * Never call remote translation API in a public request.
 */
function p12_paths(): array {
    return [
        '/' => 'Strona główna',
        '/andrzej-polan' => 'Andrzej Polan',
        '/kontakt' => 'Kontakt',
        '/rezerwacja' => 'Rezerwacja',
        '/galeria' => 'Galeria',
        '/alergeny' => 'Alergeny',
        '/polityka-prywatnosci' => 'Polityka prywatności',
        '/wspolpraca' => 'Współpraca',
        '/opinie' => 'Opinie',
        '/blog' => 'Blog — lista wpisów',
        '/blog-post' => 'Blog — szablon artykułu',
        '/menu' => 'Menu — teksty strony (pozycje tłumaczy V9)',
        '/newsletter.php' => 'Newsletter — formularz i teksty',
        '/opinia' => 'Wystaw opinię — formularz',
    ];
}
function p12_path(): ?string {
    $uri=(string)($_SERVER['REQUEST_URI']??'/');
    $path=parse_url($uri,PHP_URL_PATH) ?: '/';
    if(function_exists('p11_base_path'))$path=p11_base_path($path);
    if($path!=='/')$path=rtrim($path,'/');
    if(preg_match('~^/blog/[a-z0-9-]+$~',$path))return '/blog-post';
    return array_key_exists($path,p12_paths())?$path:null;
}
function p12_schema(): void {
    db()->exec("CREATE TABLE IF NOT EXISTS polana_v12_page_phrases (
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
        path VARCHAR(180) NOT NULL, lang CHAR(2) NOT NULL,
        source_hash CHAR(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
        source_text TEXT NOT NULL, translated_text TEXT NULL,
        status VARCHAR(16) NOT NULL DEFAULT 'pending',
        attempts SMALLINT UNSIGNED NOT NULL DEFAULT 0,
        error_text VARCHAR(500) NULL,
        seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        UNIQUE KEY uq_page_phrase(path,lang,source_hash),
        KEY ix_pending(status,attempts,id),
        KEY ix_page(path,lang,status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}
function p12_phrase(string $raw): ?array {
    // Collapse insignificant whitespace; preserve visible HTML by encoding only replacements.
    $decoded=html_entity_decode(trim($raw),ENT_QUOTES|ENT_HTML5,'UTF-8');
    $normal=trim((string)preg_replace('/\s+/u',' ',$decoded));
    if($normal===''||strlen($normal)>3200||mb_strlen($normal,'UTF-8')<3)return null;
    if(!preg_match('/\p{L}/u',$normal))return null;
    // Skip identifiers, personal data and technical elements.
    if(preg_match('~(?:https?://|www\.|mailto:|\S+@\S+|^\+?[\d\s().-]{8,}$)~iu',$normal))return null;
    if(in_array($normal,['Moja Polana Smaków','Andrzej Polan','PL','EN','DE','ES','PDF','Word','Google','Facebook','Instagram'],true))return null;
    return [$normal,hash('sha256',$normal)];
}
function p12_cached(string $path,string $lang): array {
    if(!in_array($lang,['en','de','es'],true))return [];
    try{
        $q=db()->prepare("SELECT source_hash,translated_text FROM polana_v12_page_phrases WHERE path=? AND lang=? AND status='approved'");
        $q->execute([$path,$lang]);
        $out=[];
        foreach($q->fetchAll(PDO::FETCH_ASSOC) as $r){
            if(trim((string)$r['translated_text'])!=='')$out[$r['source_hash']]=$r['translated_text'];
        }
        return $out;
    }catch(Throwable $e){error_log('POLANA V12 cached: '.$e->getMessage());return [];}
}
function p12_add_phrases(string $path,array $phrases): void {
    if(!$phrases)return;
    p12_schema();
    $stmt=db()->prepare("INSERT INTO polana_v12_page_phrases(path,lang,source_hash,source_text,status,seen_at)
       VALUES(?,?,?,?,'pending',NOW())
       ON DUPLICATE KEY UPDATE seen_at=NOW()");
    foreach($phrases as [$text,$hash]){
        foreach(['en','de','es'] as $lang)$stmt->execute([$path,$lang,$hash,$text]);
    }
}
function p12_apply_html(string $html,string $path,string $lang,bool $scan=false): string {
    // Deliberately preserve the original HTML bytes and all JS/CSS/SVG blocks.
    // Transform only visible text nodes. Never run DOMDocument HTML serialization.
    $translations=$lang==='pl'?[]:p12_cached($path,$lang);
    $seen=[];$stack=[];$blocked=[];
    $pattern='~(<script\b[^>]*>.*?</script\s*>|<style\b[^>]*>.*?</style\s*>|<svg\b[^>]*>.*?</svg\s*>|<!--.*?-->|<[^>]+>)~si';
    $parts=preg_split($pattern,$html,-1,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
    if($parts===false)return $html;
    $skipTags=['head','script','style','noscript','svg','textarea','code','pre','iframe','select'];
    $attrPattern=<<<'REGEX'
~\b(placeholder|title|aria-label|alt)\s*=\s*(["'])(.*?)\2~isu
REGEX;
    $voids=['br','img','meta','link','input','hr','source','embed','area','base','col','track','wbr','param'];
    $result='';
    foreach($parts as $part){
        if($part!==''&&$part[0]==='<'){
            // Whole script/style/svg tokens include their own closing tags.
            if(preg_match('~^<(script|style|svg)\b[^>]*>.*</\1\s*>$~si',$part)){$result.=$part;continue;}
            if(preg_match('~^<\s*/\s*([a-z][\w:-]*)~i',$part,$match)){
                $tag=strtolower($match[1]);
                // Recover from imperfect HTML nesting without affecting markup.
                for($n=count($stack)-1;$n>=0;$n--){
                    if($stack[$n]===$tag){$stack=array_slice($stack,0,$n);$blocked=array_slice($blocked,0,$n);break;}
                }
            }elseif(preg_match('~^<\s*([a-z][\w:-]*)~i',$part,$match)){
                $tag=strtolower($match[1]);
                if(!in_array($tag,$voids,true)&&!str_ends_with(trim($part),'/>')){
                    $stack[]=$tag;
                    $blocked[]=(bool)preg_match('~(?:class|id)\s*=\s*["\'][^"\']*(?:p11-language-bar|google-reviews-strip__widget|review-comment|review-content|testimonial-text|user-generated|comments-list|blog-grid|blog-article-head|blog-article-image|blog-content|menu-item|menu-category|menu-card)[^"\']*["\']~i',$part);
                }
            }
            // Visible UI labels and image descriptions also require translation.
            // Never modify URLs, scripts, event handlers or user-entered form values.
            if(($scan||$lang!=='pl')&&!array_intersect($skipTags,$stack)&&!in_array(true,$blocked,true)
                &&preg_match('~^<[a-z]~i',$part)&&!preg_match('~(?:class|id)\s*=\s*["\'][^"\']*(?:p11-language-bar|google-reviews-strip__widget|review-content|user-generated|blog-grid|blog-article-head|blog-article-image|blog-content|menu-item|menu-category|menu-card)[^"\']*["\']~i',$part)){
                $part=preg_replace_callback($attrPattern,static function(array $m)use(&$seen,$scan,$lang,$translations):string{
                    $phrase=p12_phrase($m[3]);
                    if(!$phrase)return $m[0];
                    [$text,$hash]=$phrase;
                    if($scan)$seen[$hash]=[$text,$hash];
                    if($lang!=='pl'&&isset($translations[$hash]))
                        return $m[1].'='.$m[2].htmlspecialchars($translations[$hash],ENT_QUOTES|ENT_SUBSTITUTE|ENT_HTML5,'UTF-8').$m[2];
                    return $m[0];
                },$part)??$part;
            }
            $result.=$part;continue;
        }
        if(!$scan&&$lang==='pl'){$result.=$part;continue;}
        if(array_intersect($skipTags,$stack)||in_array(true,$blocked,true)){$result.=$part;continue;}
        $phrase=p12_phrase($part);
        if(!$phrase){$result.=$part;continue;}
        [$text,$hash]=$phrase;
        if($scan)$seen[$hash]=[$text,$hash];
        if($lang!=='pl'&&isset($translations[$hash])){
            preg_match('/^(\s*)(.*?)(\s*)$/us',$part,$sp);
            $translated=htmlspecialchars($translations[$hash],ENT_QUOTES|ENT_SUBSTITUTE|ENT_HTML5,'UTF-8');
            $result.=($sp[1]??'').$translated.($sp[3]??'');
        }else{$result.=$part;}
    }
    if($scan){
        try{p12_add_phrases($path,array_values($seen));}
        catch(Throwable $e){error_log('POLANA V12 scan: '.$e->getMessage());}
    }
    return $result;
}
function p12_boot(): void {
    static $started=false;
    if($started||PHP_SAPI==='cli')return;
    $path=p12_path();if($path===null)return;
    $lang=function_exists('p11_lang')?p11_lang():'pl';
    $scan=false;
    if(isset($_GET['p12_scan'])){
        $provided=(string)$_GET['p12_scan'];
        // Authorized admin + CSRF only; public visitors never enqueue jobs.
        if($provided!=='' && is_logged_in()){
            $user=admin_user();
            $scan=(($user['role']??'')==='admin')&&hash_equals(csrf_token(),$provided)&&$lang==='pl';
        }
        if(!$scan)return;
        header('Cache-Control: private, no-store');
        header('Referrer-Policy: no-referrer');
    }
    if($lang==='pl'&&!$scan)return;
    $started=true;
    ob_start(static fn(string $html):string => p12_apply_html($html,$path,$lang,$scan));
}
function p12_key(): string {
    // Reuse exactly the production V9 resolver whenever available.
    $v9=__DIR__.'/tklm_v9.php';
    if(is_file($v9))require_once $v9;
    if(function_exists('v9_resolve_translate_key'))return v9_resolve_translate_key();
    throw new RuntimeException('Brak V9: includes/tklm_v9.php z dzialajacym odczytem keys.php.');
}
function p12_work(int $limit=1): array {
    require_once __DIR__.'/TklmTranslateClient.php';
    require_once __DIR__.'/polana_v14_names.php';
    $api=new TklmTranslateClient(p12_key());
    $q=db()->query("SELECT * FROM polana_v12_page_phrases WHERE status='pending' AND attempts<3 ORDER BY id LIMIT ".max(1,min(2,$limit)));
    $rows=$q->fetchAll(PDO::FETCH_ASSOC);
    $done=0;$failed=0;
    foreach($rows as $job){
        try{
            $translation=p14_translate($api,(string)$job['source_text'],(string)$job['lang']);
            if($translation===''||mb_strlen($translation,'UTF-8')>6000)throw new RuntimeException('Brak wyniku lub zbyt długi tekst');
            $s=db()->prepare("UPDATE polana_v12_page_phrases SET translated_text=?,status='review',error_text=NULL WHERE id=? AND status='pending'");
            $s->execute([$translation,$job['id']]);$done++;
        }catch(Throwable $e){
            $s=db()->prepare("UPDATE polana_v12_page_phrases SET attempts=attempts+1,error_text=? WHERE id=?");
            $s->execute([mb_substr($e->getMessage(),0,500),$job['id']]);$failed++;
        }
    }
    return ['attempted'=>count($rows),'translated'=>$done,'errors'=>$failed];
}
function p12_counts(): array {
    $out=['pending'=>0,'review'=>0,'approved'=>0,'errors'=>0];
    $rows=db()->query("SELECT status,COUNT(*) n FROM polana_v12_page_phrases GROUP BY status")->fetchAll(PDO::FETCH_ASSOC);
    foreach($rows as $r){$status=$r['status'];if(isset($out[$status]))$out[$status]=(int)$r['n'];}
    $q=db()->query("SELECT COUNT(*) FROM polana_v12_page_phrases WHERE status='pending' AND attempts>=3");
    $out['errors']=(int)$q->fetchColumn();$out['pending']=max(0,$out['pending']-$out['errors']);
    return $out;
}
function p12_approve(array $ids): array {
    $ok=0;$failed=[];
    $ids=array_unique(array_filter(array_map('intval',$ids),static fn($v)=>$v>0));
    if(count($ids)>300)throw new RuntimeException('Maksymalnie 300 pozycji w jednym zatwierdzeniu.');
    $get=db()->prepare("SELECT path,lang,status,source_text FROM polana_v12_page_phrases WHERE id=?");
    $set=db()->prepare("UPDATE polana_v12_page_phrases SET status='approved' WHERE id=? AND status='review' AND translated_text IS NOT NULL AND translated_text<>''");
    foreach($ids as $id){
        $get->execute([$id]);$row=$get->fetch(PDO::FETCH_ASSOC);
        if(!$row||!isset(p12_paths()[$row['path']])||!in_array($row['lang'],['en','de','es'],true)||$row['status']!=='review'){$failed[]=$id;continue;}
        $set->execute([$id]);if($set->rowCount())$ok++;else $failed[]=$id;
    }
    return ['approved'=>$ok,'failed'=>$failed];
}

Youez - 2016 - github.com/yon3zu
LinuXploit