| 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);
require_once dirname(__DIR__).'/includes/functions.php';
require_once dirname(__DIR__).'/includes/polana_v175_patch_lib.php';
require_admin_role();
header('Cache-Control: private, no-store');
header('X-Robots-Tag: noindex,nofollow');
function pv175_install_root():string {return dirname(__DIR__);}
function pv175_install_backup_base():string {return dirname(dirname(pv175_install_root())).'/.polana_v175_private_backups';}
function pv175_install_targets():array {
$r=pv175_install_root();
return ['includes/reservations.php'=>$r.'/includes/reservations.php','rezerwacja.php'=>$r.'/rezerwacja.php','admin/reservation-settings.php'=>$r.'/admin/reservation-settings.php','includes/functions.php'=>$r.'/includes/functions.php'];
}
function pv175_install_write(string $file,string $content):void {
$temp=$file.'.pv175_'.bin2hex(random_bytes(5)).'.tmp';
if (@file_put_contents($temp,$content,LOCK_EX)!==strlen($content)) {@unlink($temp);throw new RuntimeException('Nie można zapisać '.basename($file));}
$perms=@fileperms($file);
if($perms!==false) @chmod($temp,$perms&0777);
if(!@rename($temp,$file)) {@unlink($temp);throw new RuntimeException('Nie można podmienić '.basename($file));}
}
function pv175_install_prepare():array {
$root=pv175_install_root();
foreach(['includes/polana_v175_booking.php','polana-rezerwacje-godziny.php','admin/polana-godziny-rezerwacji.php'] as $needed) {
if(!is_file($root.'/'.$needed)) throw new RuntimeException('Brak pliku '.$needed.' — wgraj najpierw cały katalog DO_WGRANIA.');
}
$changes=[];
foreach(pv175_install_targets() as $relative=>$file){
if(!is_file($file)||!is_readable($file)||!is_writable($file)) throw new RuntimeException('Brak uprawnień do pliku '.$relative);
$original=file_get_contents($file);
if(!is_string($original)) throw new RuntimeException('Błąd odczytu '.$relative);
$normal=str_replace("\r\n","\n",$original);
$patched=pv175_patch($relative,$normal);
$after=str_contains($original,"\r\n") ? str_replace("\n","\r\n",$patched) : $patched;
if($original!==$after)$changes[$relative]=['file'=>$file,'before'=>$original,'after'=>$after];
}
return $changes;
}
function pv175_install_run():string {
$changes=pv175_install_prepare();
if(!$changes) return 'V17.5 jest już zainstalowana — pliki pozostawiono bez zmian.';
$base=pv175_install_backup_base();
if(!is_dir($base)&&!@mkdir($base,0700,true))throw new RuntimeException('Nie można utworzyć prywatnego katalogu kopii poza WWW.');
if(!is_writable($base))throw new RuntimeException('Brak uprawnień do katalogu kopii.');
@file_put_contents($base.'/.htaccess',"Require all denied\nDeny from all\n");
$folder=$base.'/'.date('Ymd_His').'_'.bin2hex(random_bytes(4));
if(!@mkdir($folder,0700))throw new RuntimeException('Nie można utworzyć kopii.');
$manifest=['version'=>'17.5','created_at'=>date('c'),'files'=>[],'rolled_back'=>false];
foreach($changes as $relative=>$data){
$backup=$folder.'/'.str_replace('/','__',$relative).'.bak';
if(@file_put_contents($backup,$data['before'],LOCK_EX)!==strlen($data['before']))throw new RuntimeException('Błąd kopii: '.$relative);
$manifest['files'][$relative]=['backup'=>basename($backup),'after_sha256'=>hash('sha256',$data['after'])];
}
if(@file_put_contents($folder.'/manifest.json',json_encode($manifest,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR),LOCK_EX)===false)throw new RuntimeException('Nie można zapisać manifestu kopii.');
$written=[];
try {
foreach($changes as $relative=>$data){pv175_install_write($data['file'],$data['after']);$written[]=$relative;}
} catch(Throwable $e){
foreach(array_reverse($written) as $relative){
try{pv175_install_write($changes[$relative]['file'],$changes[$relative]['before']);}catch(Throwable $restore){error_log('[POLANA V175 rollback-on-fail] '.$restore->getMessage());}
}
$manifest['rolled_back']=true;
@file_put_contents($folder.'/manifest.json',json_encode($manifest,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE),LOCK_EX);
throw $e;
}
return 'Zainstalowano V17.5. Zmieniono '.count($written).' pliki. Kopia: '.basename($folder).'. Teraz ustaw godziny i włącz blokadę.';
}
function pv175_install_latest():?array {
$base=pv175_install_backup_base();
$folders=glob($base.'/*/manifest.json')?:[];
rsort($folders,SORT_STRING);
foreach($folders as $manifestPath){
$data=json_decode((string)@file_get_contents($manifestPath),true);
if(is_array($data)&&($data['version']??'')==='17.5'&&empty($data['rolled_back']))return ['path'=>$manifestPath,'data'=>$data];
}
return null;
}
function pv175_install_rollback():string {
$latest=pv175_install_latest();
if(!$latest)throw new RuntimeException('Nie znaleziono aktywnej kopii V17.5.');
$manifest=$latest['data'];$path=$latest['path'];$folder=dirname($path);
$restores=[];
foreach($manifest['files'] as $relative=>$meta){
$targets=pv175_install_targets();
if(!isset($targets[$relative]))throw new RuntimeException('Nieznany plik kopii: '.$relative);
$file=$targets[$relative];$current=@file_get_contents($file);
if(!is_string($current)||!hash_equals($meta['after_sha256'],hash('sha256',$current)))throw new RuntimeException('Plik '.$relative.' zmienił się po instalacji — rollback wstrzymany, by nie utracić późniejszych zmian.');
$backup=$folder.'/'.$meta['backup'];$original=@file_get_contents($backup);
if(!is_string($original))throw new RuntimeException('Brak kopii '.$relative);
$restores[$relative]=['file'=>$file,'content'=>$original];
}
foreach($restores as $data)pv175_install_write($data['file'],$data['content']);
$manifest['rolled_back']=true;
if(@file_put_contents($path,json_encode($manifest,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR),LOCK_EX)===false)throw new RuntimeException('Przywrócono pliki, ale nie można zapisać znacznika rollbacku.');
return 'Przywrócono oryginalne pliki V17.5. Ustawienia godzin pozostawiono w bazie; bez integracji nie blokują formularza.';
}
if($_SERVER['REQUEST_METHOD']==='POST'){
verify_csrf();
try {
$action=(string)($_POST['action']??'');
if($action==='install')$msg=pv175_install_run();
elseif($action==='rollback'){
if(($_POST['confirm_rollback']??'')!=='1')throw new RuntimeException('Potwierdź cofnięcie zmian.');
$msg=pv175_install_rollback();
} else throw new RuntimeException('Nieznana operacja.');
flash('success',$msg);
} catch(Throwable $e){flash('error',$e->getMessage());}
redirect('/admin/polana-v175-instalator.php');
}
$installed=false;$status='';
try{$changes=pv175_install_prepare();$installed=count($changes)===0;$status=$installed?'Zainstalowana':'Gotowa do instalacji';}
catch(Throwable $e){$status='Wymaga uwagi: '.$e->getMessage();}
render_admin_header('Instalator V17.5');
?>
<div style="max-width:920px;margin:25px auto;padding:0 14px">
<div class="form-card" style="padding:26px;border-radius:18px">
<h1>Polana V17.5 — godziny i wiadomości HTML</h1>
<p>Bezpieczny instalator: najpierw sprawdza kod, potem zapisuje kopie poza katalogiem WWW, a dopiero później aktualizuje wskazane fragmenty. Nie modyfikuje SMTP, Google Kalendarza, SEO ani rezerwacji w bazie.</p>
<p><strong>Stan:</strong> <?= e($status) ?></p>
<form method="post"><?= csrf_field() ?><input type="hidden" name="action" value="install"><button type="submit" class="btn btn-primary" <?= str_starts_with($status,'Wymaga')?'disabled':'' ?>>Zainstaluj V17.5 z backupem</button></form>
<p style="margin-top:18px"><a href="/admin/polana-godziny-rezerwacji.php">Godziny rezerwacji i podgląd e-maili →</a> · <a href="/admin/reservation-settings.php">Ustawienia rezerwacji →</a></p>
</div>
<div class="form-card" style="margin-top:18px;padding:24px"><h2>Rollback</h2><p>Cofnięcie tylko zmian V17.5, jeśli pliki nie były później edytowane. Nie usuwa nowych rezerwacji ani ustawień SMTP.</p>
<form method="post"><?= csrf_field() ?><input type="hidden" name="action" value="rollback"><label><input type="checkbox" name="confirm_rollback" value="1" required> Potwierdzam cofnięcie V17.5</label> <button class="btn btn-light" type="submit">Cofnij V17.5</button></form>
</div>
</div>
<?php render_admin_footer(); ?>