| 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 : |
<?php
declare(strict_types=1);
/** Pure patch functions: fail closed on unknown structures; no writes here. */
function pv175_once(string $content,string $needle,string $replace,string $label):string {
if(substr_count($content,$needle)!==1) throw new RuntimeException('Nie znaleziono jednoznacznego wzorca: '.$label.'. Nie nadpisano plików.');
return str_replace($needle,$replace,$content);
}
function pv175_patch_reservations(string $content):string {
if (str_contains($content,'POLANA_V175_RESERVATIONS')) return $content;
$content=pv175_once($content,'function reservation_validate_public_input(array $input): array','/* POLANA_V175_RESERVATIONS */' . "\n" . "require_once __DIR__.'/polana_v175_booking.php';\n\nfunction reservation_validate_public_input(array \$input): array",'reservation_validate_public_input');
$needle=" return [\n 'errors' => \$errors,";
$insert=" /* POLANA_V175_SERVER_VALIDATION — no bypass by manual POST */\n \$slotCheck = pv175_validate_slot(\$date, \$time);\n if (!\$slotCheck['ok']) \$errors[] = \$slotCheck['message'];\n\n".$needle;
$content=pv175_once($content,$needle,$insert,'return validation errors');
// Restrict each replacement to the appropriate function to avoid touching SMTP tests.
$adminNeedle="reservation_email_html('Nowa rezerwacja', \$body)";
$content=pv175_once($content,$adminNeedle,"pv175_email_html('Nowa rezerwacja', \$body, \$reservation, 'admin')",'admin reservation email');
$guestNeedle='reservation_email_html($subject, $body)';
$content=pv175_once($content,$guestNeedle,'pv175_email_html($subject, $body, $reservation, $kind)','guest reservation email');
// Also cover installations where V17.2 Reply-To was not installed yet.
$withoutReply = " pv175_email_html(\$subject, \$body, \$reservation, \$kind),\n \$body\n );";
$withReply = " pv175_email_html(\$subject, \$body, \$reservation, \$kind),\n \$body,\n trim(reservation_setting('reservation_admin_email')) ?: null\n );";
if (str_contains($content, $withoutReply)) {
$content=pv175_once($content,$withoutReply,$withReply,'guest Reply-To');
}
return $content;
}
function pv175_patch_rezerwacja(string $content):string {
if(str_contains($content,'POLANA_V175_PUBLIC_HOURS')) return $content;
$pattern='~<label>\s*Godzina\s*<input\b[^>]*\btype="time"\b[^>]*\bname="reservation_time"\b[^>]*>\s*</label>~s';
// More tolerant attribute matching: \b after a closing quote is not guaranteed.
$pattern='~<label>\s*Godzina\s*<input\s+type="time"\s+name="reservation_time".*?\s*>\s*</label>~s';
if(preg_match_all($pattern,$content,$matches)!==1) throw new RuntimeException('Nie znaleziono jednoznacznego pola godziny w rezerwacja.php. Nie nadpisano plików.');
$original=$matches[0][0];
$replacement=<<<'TPL'
<!-- POLANA_V175_PUBLIC_HOURS -->
<?php if (pv175_enabled()): ?>
<label>
Godzina
<select name="reservation_time" id="pv175-time" required aria-describedby="pv175-hint">
<option value="">Najpierw wybierz datę</option>
</select>
<small id="pv175-hint" style="display:block;color:#666;margin-top:5px">Wybierz datę, aby zobaczyć dostępne godziny.</small>
</label>
<?php else: ?>
TPL;
$replacement.="\n".$original."\n<?php endif; ?>";
$content=pv175_once($content,$original,$replacement,'reservation time input');
$script=<<<'SCRIPT'
<!-- POLANA_V175_PUBLIC_HOURS_SCRIPT -->
<?php if (pv175_enabled()): ?>
<script>
(function(){
const dateInput=document.querySelector('input[name="reservation_date"]');
const timeSelect=document.getElementById('pv175-time');
const hint=document.getElementById('pv175-hint');
if(!dateInput||!timeSelect||!hint)return;
const selectedOnSubmit=<?= json_encode((string)($_POST['reservation_time']??''), JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT) ?>;
let requestNo=0;
async function refresh(){
const id=++requestNo;
timeSelect.replaceChildren(new Option('Sprawdzam dostępne godziny…',''));
timeSelect.disabled=true;
if(!dateInput.value){timeSelect.replaceChildren(new Option('Najpierw wybierz datę',''));hint.textContent='Wybierz datę.';return;}
try{
const response=await fetch('/polana-rezerwacje-godziny.php?date='+encodeURIComponent(dateInput.value),{credentials:'same-origin',cache:'no-store'});
if(!response.ok)throw new Error('Błąd sprawdzania godzin');
const data=await response.json();
if(id!==requestNo)return;
timeSelect.replaceChildren(new Option(data.slots?.length?'Wybierz godzinę':'Brak dostępnych godzin',''));
for(const slot of (data.slots||[]))timeSelect.add(new Option(slot,slot));
const oldValue=(id===1?selectedOnSubmit:'');
if(oldValue&&data.slots.includes(oldValue))timeSelect.value=oldValue;
timeSelect.disabled=!data.slots?.length;
hint.textContent=data.message||'';
hint.style.color=data.slots?.length?'#566a56':'#9a442f';
}catch(err){
if(id!==requestNo)return;
timeSelect.replaceChildren(new Option('Nie można sprawdzić godzin',''));
timeSelect.disabled=true;
hint.textContent='Nie udało się pobrać godzin. Odśwież stronę i spróbuj ponownie.';
hint.style.color='#9a442f';
}
}
dateInput.addEventListener('change',refresh);
refresh();
})();
</script>
<?php endif; ?>
SCRIPT;
$content=pv175_once($content,'</main>',"</main>\n".$script,'public page main closing');
return $content;
}
function pv175_patch_settings(string $content):string {
if(str_contains($content,'POLANA_V175_SETTINGS_LINK')) return $content;
$needle='<form class="form-card form-grid" method="post">';
if(substr_count($content,$needle)<1) return $content;
$link='<div class="form-card" style="margin-bottom:18px;padding:18px"><strong>Godziny rezerwacji i wygląd e-maili</strong><p style="margin:7px 0 12px">Ustaw dni otwarcia, zablokuj niedostępne godziny i zobacz podgląd autoresponderów.</p><a class="btn btn-primary" href="/admin/polana-godziny-rezerwacji.php">Otwórz godziny i wiadomości →</a></div>';
$pos=strpos($content,$needle);
return substr_replace($content,"<!-- POLANA_V175_SETTINGS_LINK -->\n".$link."\n",$pos,0);
}
function pv175_patch_nav(string $content):string {
if(str_contains($content,'POLANA_V175_NAV')) return $content;
$needle='<a href="/admin/">Pulpit</a>';
if(substr_count($content,$needle)!==1) return $content;
$extra="\n <!-- POLANA_V175_NAV -->\n <?php if (\$role === 'admin'): ?><a href=\"/admin/polana-godziny-rezerwacji.php\">Godziny rezerwacji</a><?php endif; ?>";
return str_replace($needle,$needle.$extra,$content);
}
function pv175_patch(string $relative,string $content):string {
return match($relative) {
'includes/reservations.php'=>pv175_patch_reservations($content),
'rezerwacja.php'=>pv175_patch_rezerwacja($content),
'admin/reservation-settings.php'=>pv175_patch_settings($content),
'includes/functions.php'=>pv175_patch_nav($content),
default=>throw new RuntimeException('Nieobsługiwany plik: '.$relative),
};
}