| 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 : |
<?php
declare(strict_types=1);
/** POLANA V18.8 — migracja indeksowanego menu-seo do jednego /menu. */
require_once dirname(__DIR__).'/includes/functions.php';
require_admin_role();
header('Cache-Control: private, no-store');
header('X-Robots-Tag: noindex,nofollow');
function p188e($x):string{return htmlspecialchars((string)$x,ENT_QUOTES|ENT_SUBSTITUTE,'UTF-8');}
function p188read(string $p):string{$v=@file_get_contents($p);if(!is_string($v))throw new RuntimeException('Brak dostępu do pliku: '.basename($p));return $v;}
function p188one(string $hay,string $needle,string $replacement,string $where):string{
$n=substr_count($hay,$needle);
if($n!==1)throw new RuntimeException($where.': nieznana wersja pliku (oczekiwano jednego znacznika, znaleziono '.$n.'). Niczego nie instalowano.');
return str_replace($needle,$replacement,$hay);
}
function p188patch(string $rel,string $source):string{
$source=str_replace("\r\n", "\n", $source);
if($rel==='menu.php'){
if(str_contains($source,'POLANA_V18_8_MENU_SEO'))throw new RuntimeException('Menu V18.8 już jest zmodyfikowane — najpierw sprawdź manifest.');
$source=p188one($source,"require_once __DIR__ . '/includes/functions.php';", "/* POLANA_V18_8_MENU_SEO */\nrequire_once __DIR__ . '/includes/polana_menu_seo_v188.php';\np188_menu_boot();\nrequire_once __DIR__ . '/includes/functions.php';",$rel);
$old="render_public_head(\n \$seoTitle,\n \$seoDescription,\n '/menu',\n null,\n 'noindex,follow'\n);";
$new="[\$seoTitle, \$seoDescription] = p188_meta(\$menuType, \$seoTitle, \$seoDescription);\nrender_public_head(\n \$seoTitle,\n \$seoDescription,\n '/menu' . (\$menuType === 'food' ? '' : '?kind=' . rawurlencode(\$menuType)),\n p188_schema(\$dbMenu, \$menuType),\n p188_robots(\$dbMenu, \$menuType)\n);";
$source=p188one($source,$old,$new,$rel);
$source=p188one($source,'</main>' . "\n\n" . '<div class="menu-fullscreen"','</main>' . "\n" . '<?php p188_render_text($dbMenu, $menuType); ?>' . "\n\n" . '<style>.p188-text-menu{background:#f5f3ed;color:#252522;padding:28px 14px 65px}.p188-text-menu-inner{max-width:820px;margin:auto}.p188-text-menu h2{font-size:clamp(24px,4vw,34px);margin:0 0 24px}.p188-category{margin:22px 0}.p188-category h3{font-size:22px;padding-bottom:10px;border-bottom:1px solid #d5cfbf}.p188-dish{padding:11px 0;border-bottom:1px solid #e2ddd3}.p188-dish-head{display:flex;justify-content:space-between;gap:16px;align-items:baseline}.p188-dish-head span{white-space:nowrap;font-weight:700}.p188-dish p{margin:6px 0;color:#57534b;font-size:14px;line-height:1.5}</style>' . "\n" . '<div class="menu-fullscreen"',$rel);
$source=p188one($source,"href=\"<?= e(p15_menu_url('/menu-seo',\$menuType)) ?>\"","href=\"#menu-tekst\"",$rel);
return $source;
}
if($rel==='menu-seo.php'){
if(str_contains($source,'POLANA_V18_8_REDIRECT'))throw new RuntimeException('Przekierowanie jest już w kodzie.');
return p188one($source,"declare(strict_types=1);","declare(strict_types=1);\n/* POLANA_V18_8_REDIRECT — dawna wersja tekstowa teraz jest w /menu */\nrequire_once __DIR__ . '/includes/polana_menu_seo_v188.php';\np188_legacy_redirect();",$rel);
}
if($rel==='includes/functions.php'){
return p188one($source, "'menu' => site_url(polana_local_path('/menu-seo'))", "'menu' => site_url(polana_local_path('/menu'))", $rel);
}
if($rel==='includes/polana_domain.php'){
if(str_contains($source,"'https://mojapolanasmakow.pl'"))return $source;
return p188one($source,"define('POLANA_PUBLIC_ORIGIN', 'https://polanasmakow.pl');","define('POLANA_PUBLIC_ORIGIN', 'https://mojapolanasmakow.pl');",$rel);
}
if(in_array($rel,['includes/polana_v164_seo.php','includes/polana_v166_seo.php'],true)){
if(!str_contains($source,"\$url='/menu-seo'"))throw new RuntimeException('Sitemap: nieznana logika generatora. Nic nie zmieniono.');
$source=p188one($source,"\$url='/menu-seo'.(","\$url='/menu'.(",$rel);
$source=p188one($source,"is_file(\$root.'/menu-seo.php')","is_file(\$root.'/menu.php')",$rel);
return $source;
}
throw new RuntimeException('Nieobsługiwana ścieżka: '.$rel);
}
function p188files(string $root):array{
$base=['menu.php','menu-seo.php','includes/polana_domain.php','includes/functions.php'];
$seo=is_file($root.'/includes/polana_v164_seo.php')?'includes/polana_v164_seo.php':'includes/polana_v166_seo.php';
$base[]=$seo;
foreach($base as $rel){$p=$root.'/'.$rel;if(!is_file($p)||is_link($p))throw new RuntimeException('Nie ma zwykłego pliku: '.$rel);}
return $base;
}
function p188backupbase(string $root):string{
// Katalog o realpath poza public_html, bez fallbacku do storage w WWW.
$private=null;
$lib=$root.'/includes/polana_backup_v182.php';
if(is_file($lib)){
try{require_once $lib; if(function_exists('pbk_private'))$private=pbk_private();}catch(Throwable $ignore){}
}
$parents=[($private!==null?$private:null),dirname($root).'/.polana-private-ops'];
foreach($parents as $candidate){
if(!is_string($candidate)||$candidate==='')continue;
if(!is_dir($candidate)&&!@mkdir($candidate,0700,true))continue;
$real=realpath($candidate);
if($real===false||str_starts_with($real.'/', $root.'/')||!is_writable($real))continue;
$target=$real.'/polana-v188-menu-seo';
if(!is_dir($target)&&!@mkdir($target,0700,true))continue;
@chmod($target,0700);
return $target;
}
throw new RuntimeException('Brak zapisywalnego katalogu poza WWW. Skonfiguruj prywatne backupy V18.3.');
}
function p188atomic(string $path,string $content):void{
if(is_link($path)||!is_file($path))throw new RuntimeException('Nieobsługiwany typ pliku.');
$tmp=tempnam(dirname($path),'.p188-');if(!$tmp)throw new RuntimeException('Nie można przygotować pliku tymczasowego.');
$mode=fileperms($path)&0777;
try{
if(file_put_contents($tmp,$content,LOCK_EX)!==strlen($content))throw new RuntimeException('Niepełny zapis pliku tymczasowego.');
@chmod($tmp,$mode);
if(!@rename($tmp,$path))throw new RuntimeException('Nie można podmienić pliku.');
}finally{if(is_file($tmp))@unlink($tmp);}
}
function p188manifest(string $base):?array{
$path=$base.'/active.json';if(!is_file($path))return null;
$data=json_decode(p188read($path),true);if(!is_array($data))throw new RuntimeException('Uszkodzony manifest aktywnej instalacji.');
return $data;
}
function p188install(string $root,string $base):string{
if(p188manifest($base))throw new RuntimeException('V18.8 została już zainstalowana.');
$original=[];$patched=[];
foreach(p188files($root) as $rel){
$original[$rel]=p188read($root.'/'.$rel);
$patched[$rel]=p188patch($rel,$original[$rel]);
}
$lib=$root.'/includes/polana_menu_seo_v188.php';
if(!is_file($lib)||!str_contains(p188read($lib),'function p188_render_text'))throw new RuntimeException('Brak biblioteki SEO V18.8 — wgraj całe DO_WGRANIA.');
$id=gmdate('Ymd-His').'-'.bin2hex(random_bytes(4));$dir=$base.'/'.$id;
if(!@mkdir($dir,0700))throw new RuntimeException('Nie można stworzyć katalogu backupu.');
$meta=['version'=>'18.8','id'=>$id,'files'=>[],'created_utc'=>gmdate('c')];
foreach($original as $rel=>$s){
$save=$dir.'/'.str_replace('/','__',$rel).'.orig';
if(file_put_contents($save,$s,LOCK_EX)!==strlen($s))throw new RuntimeException('Nie udało się zapisać wszystkich oryginałów.');
@chmod($save,0600);
$meta['files'][$rel]=['old'=>hash('sha256',$s),'new'=>hash('sha256',$patched[$rel])];
}
$done=[];
try{
foreach($patched as $rel=>$contents){
p188atomic($root.'/'.$rel,$contents);$done[]=$rel;
if(hash_file('sha256',$root.'/'.$rel)!==$meta['files'][$rel]['new'])throw new RuntimeException('Błąd integralności po zapisie: '.$rel);
}
$json=json_encode($meta,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_THROW_ON_ERROR);
$tmp=$base.'/active.tmp';
if(file_put_contents($tmp,$json,LOCK_EX)!==strlen($json)||!@rename($tmp,$base.'/active.json'))throw new RuntimeException('Nie zapisano manifestu.');
}catch(Throwable $e){
foreach(array_reverse($done) as $rel){try{p188atomic($root.'/'.$rel,$original[$rel]);}catch(Throwable $ignore){}}
throw $e;
}
if(function_exists('admin_log'))admin_log('polana_v188_seo_install','Menu SEO /menu + 301 /menu-seo');
return 'Zainstalowano. Wcześniejsze pliki zapisano poza WWW. Testuj /menu, /menu-seo i sitemap.xml.';
}
function p188rollback(string $root,string $base):string{
$m=p188manifest($base);if(!$m||($m['version']??'')!=='18.8')throw new RuntimeException('Nie ma aktywnej instalacji V18.8.');
$dir=$base.'/'.$m['id'];$restore=[];
foreach($m['files'] as $rel=>$sha){
$path=$root.'/'.$rel;
if(!is_file($path)||hash_file('sha256',$path)!==$sha['new'])throw new RuntimeException('Plik zmieniony po aktualizacji: '.$rel.'. Nie nadpisujemy późniejszych poprawek.');
$original=p188read($dir.'/'.str_replace('/','__',$rel).'.orig');
if(hash('sha256',$original)!==$sha['old'])throw new RuntimeException('Kopia uszkodzona: '.$rel);
$restore[$rel]=$original;
}
foreach($restore as $rel=>$s)p188atomic($root.'/'.$rel,$s);
if(!@rename($base.'/active.json',$base.'/rolled-back-'.$m['id'].'.json'))throw new RuntimeException('Pliki przywrócono, ale nie można przenieść manifestu.');
if(function_exists('admin_log'))admin_log('polana_v188_seo_rollback','Rollback SEO menu');
return 'Przywrócono oryginalne pliki SEO i menu. Biblioteka/instalator mogą pozostać nieużywane.';
}
$root=realpath(dirname(__DIR__));$msg='';$err='';$active=null;$base=null;$files=[];
try{
if(!$root)throw new RuntimeException('Nie można ustalić katalogu WWW.');
$base=p188backupbase($root);
if(($_SERVER['REQUEST_METHOD']??'GET')==='POST'){
verify_csrf();$action=(string)($_POST['action']??'');
if($action==='install')$msg=p188install($root,$base);
elseif($action==='rollback')$msg=p188rollback($root,$base);
else throw new RuntimeException('Nieznana akcja.');
}
$active=p188manifest($base);$files=p188files($root);
}catch(Throwable $e){$err=$e->getMessage();}
render_admin_header('POLANA V18.8 — SEO menu');
?>
<style>.v188{max-width:1000px;margin:28px auto;padding:15px;line-height:1.65}.v188 section{border:1px solid #8885;padding:25px;border-radius:15px;margin-bottom:16px}.v188 button{border:0;padding:12px 18px;background:#99501b;color:white;border-radius:9px;font-weight:800;cursor:pointer}.v188 .danger{background:#8d3328}.v188 .ok{border-left:4px solid #3c7b49}.v188 .error{border-left:4px solid #b82828}.v188 code{overflow-wrap:anywhere}</style>
<div class="v188">
<section><h1>POLANA V18.8 — jedno menu widoczne w Google</h1><p>Naprawa: główny adres <code>https://mojapolanasmakow.pl/menu</code>, opis SEO, indeksowanie gotowej karty, treść dań na stronie menu, przekierowanie starego <code>/menu-seo</code>, sitemap i domena kanoniczna.</p><p><strong>Instalator nie zmienia bazy ani rezerwacji.</strong> Przed instalacją wykonaj własny backup plików strony. Narzędzie dodatkowo zachowuje oryginalne zmieniane pliki poza WWW.</p></section>
<?php if($msg!==''):?><section class="ok"><strong><?=p188e($msg)?></strong></section><?php endif;?>
<?php if($err!==''):?><section class="error"><strong><?=p188e($err)?></strong></section><?php endif;?>
<?php if($base!==null):?><section><h2><?= $active?'Wersja V18.8 jest aktywna':'Gotowe do instalacji' ?></h2><p>Pliki: <code><?=p188e(implode(', ',$files))?></code></p>
<?php if(!$active && $err===''):?><form method="post"><?=csrf_field()?><input type="hidden" name="action" value="install"><button>Wykonaj backup i zainstaluj SEO menu</button></form><?php endif;?>
<?php if($active):?><form method="post"><?=csrf_field()?><input type="hidden" name="action" value="rollback"><button class="danger">Rollback — przywróć oryginalne pliki</button></form><?php endif;?></section><?php endif;?>
<section><h2>Sprawdzenie po instalacji</h2><ol><li>Wejdź na <a href="https://mojapolanasmakow.pl/menu" target="_blank" rel="noopener">/menu</a> — menu ma działać, a na dole pojawi się tekstowa karta dań.</li><li><a href="https://polanasmakow.pl/menu-seo" target="_blank" rel="noopener">Stary adres /menu-seo</a> ma przekierować 301 na nową domenę /menu.</li><li><a href="https://mojapolanasmakow.pl/sitemap.xml" target="_blank" rel="noopener">sitemap.xml</a> ma zawierać /menu zamiast /menu-seo.</li><li>Zweryfikuj PL/EN/DE/ES oraz karty napojów/win i działanie QR.</li><li>W Google Search Console poproś o ponowną indeksację /menu. Zmiana wyniku w Google trwa pewien czas.</li></ol><small>Jeżeli aktywna wersja któregoś pliku różni się od znanego kodu, instalator przerwie operację bez zmian — prześlij wtedy komunikat i bieżący plik.</small></section>
</div>
<?php render_admin_footer(); ?>