This commit is contained in:
2026-05-13 23:16:10 +02:00
parent d177dc3298
commit 98c037f040
2 changed files with 54 additions and 66 deletions

View File

@@ -52,15 +52,6 @@
</div> </div>
<? endif; ?> <? endif; ?>
<div class="panel">
<div class="panel-heading">
<span class="panel-title">Changelog</span>
</div>
<div class="panel-body">
<?= @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver ); ?>
</div>
</div>
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
var version_current = <?= $this->ver; ?>; var version_current = <?= $this->ver; ?>;
@@ -138,3 +129,19 @@ $(function() {
} }
}); });
</script> </script>
<div class="panel">
<div class="panel-heading">
<span class="panel-title">Changelog</span>
</div>
<div class="panel-body">
<?php
$changelog = (string) @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver );
// Usuń komentarze HTML i wszystkie tagi poza bezpieczną listą formatującą,
// żeby zdalny serwis nie mógł popsuć struktury strony (psuło to footer-script i przycisk "Wyczyść cache").
$changelog = preg_replace( '/<!--.*?-->/s', '', $changelog );
$changelog = strip_tags( $changelog, '<p><br><b><strong><i><em><u><ul><ol><li><h1><h2><h3><h4><h5><h6><span><div><a><pre><code><hr>' );
echo $changelog;
?>
</div>
</div>

View File

@@ -1,75 +1,56 @@
# Zmiana: Fix przekierowania w summaryView # Zmiana 3: Naprawa JS na stronie /admin/update/main_view/ (przyciski aktualizacji + Wyczyść cache)
## Plik ## Plik
`autoload/front/Controllers/ShopBasketController.php` `admin/templates/update/main-view.php`
## Problem ## Problem
Po złożeniu pierwszego zamówienia, próba złożenia drugiego zamówienia powodowała przekierowanie na stronę poprzedniego zamówienia (`/zamowienie/{hash}`) zamiast na stronę podsumowania koszyka (`/koszyk-podsumowanie`). Na podstronie `/admin/update/main_view/` nie działały:
- przycisk **„Aktualizuj do wyższej wersji"** (`#confirm`)
- przycisk **„Aktualizuj do najwyższej wersji"** (`#confirmUpdateAll`)
- globalny przycisk **„Wyczyść cache"** (`#clear-cache-btn`) z headera admina
W konsoli przeglądarki **nie było żadnego błędu JS**. Kliknięcie powodowało jedynie dopisanie `#` do URL-a (`/admin/update/main_view/#`).
## Przyczyna ## Przyczyna
W metodzie `summaryView()` był guard sprawdzający sesyjny klucz `order-submit-last-order-id`. Jeśli istniał (a istniał po każdym złożonym zamówieniu), metoda od razu redirectowała na stronę starego zamówienia — nigdy nie dochodziło do `createOrderSubmitToken()`, które czyści ten klucz. W szablonie znajdowało się pobieranie zdalnego changeloga przez `file_get_contents` z `https://shoppro.project-dc.pl/updates/changelog.php`:
## Co usunięto
Usunięto blok (dawne linie 279-290):
```php ```php
$existingOrderId = isset( $_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] ) <?= @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver ); ?>
? (int)$_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ]
: 0;
if ( $existingOrderId > 0 )
{
$existingOrderHash = $this->orderRepository->findHashById( $existingOrderId );
if ( $existingOrderHash )
{
header( 'Location: /zamowienie/' . $existingOrderHash );
exit;
}
}
``` ```
## Zabezpieczenie double-submit Odpowiedź zdalnego serwera zawierała niezbalansowany HTML (np. niezamknięty `<script>`, `<!--`, `<style>` albo `<textarea>`), który „połykał" całą resztę dokumentu jako tekst wewnątrz tego nieparzystego tagu. Skutki:
Ochrona przed podwójnym wysłaniem formularza pozostaje nienaruszona w metodzie `basketSave()` — tam ten sam mechanizm działa poprawnie. - Inline-script z handlerami przycisków aktualizacji (zaraz pod changelogiem) nie był parsowany jako JS.
- Footer-script z `main-layout.php` (handler `#clear-cache-btn` i globalne wyszukiwanie) też był „w środku" połkniętego HTML i nigdy się nie uruchamiał na tej podstronie.
- Konsola nie pokazywała błędu, bo to nie był błąd JS — to był po prostu HTML, który nigdy nie został wykonany jako skrypt.
--- ## Co zmieniono
# Zmiana 2: Logowanie błędów w basketSave + naprawa tokena zamówienia ### 1. Blok `<script>` z handlerami przeniesiony przed sekcję Changelog
Wcześniej kolejność w szablonie była: panel z wersjami → log → **changelog (zdalny)**`<script>`. Po zmianie: panel z wersjami → log → **`<script>`** → changelog (zdalny). Dzięki temu handlery `#confirm` i `#confirmUpdateAll` podpinają się niezależnie od tego, co zwróci zdalny serwer.
## Plik ### 2. Sanitizacja odpowiedzi zdalnego changeloga
`autoload/front/Controllers/ShopBasketController.php` Przed wyrenderowaniem changelog jest czyszczony:
## Problem ```php
Klientka nie mogła złożyć zamówienia — komunikat "Podczas składania zamówienia wystąpił błąd". Brak logowania uniemożliwiał diagnozę. Dodatkowo token zamówienia był jednorazowy i nadpisywany przy każdym wejściu na podsumowanie — otwarcie drugiej karty, użycie "wstecz" w przeglądarce lub odświeżenie strony unieważniało token i blokowało złożenie zamówienia. $changelog = (string) @file_get_contents( 'https://shoppro.project-dc.pl/updates/changelog.php?ver=' . $this->ver );
$changelog = preg_replace( '/<!--.*?-->/s', '', $changelog );
$changelog = strip_tags( $changelog, '<p><br><b><strong><i><em><u><ul><ol><li><h1><h2><h3><h4><h5><h6><span><div><a><pre><code><hr>' );
echo $changelog;
```
## Dodane logowanie do `logs/logs-order-{data}.log` - Usuwane są komentarze HTML (`<!--…-->`).
Dodana prywatna metoda `logOrder()` zapisująca do pliku `logs/logs-order-YYYY-MM-DD.log` (schemat jak `logs-db-*`). - `strip_tags` z wąską białą listą zostawia tylko tagi formatujące — wszystkie tagi strukturalne i mogące „połknąć" treść (`<script>`, `<style>`, `<textarea>`, `<iframe>`, `<body>`, `</html>` itp.) są usuwane.
Logowanie w 4 miejscach w `basketSave()`: ### 3. Naprawiony też skutek uboczny
Po tych zmianach poprawnie działa również:
- footer-script z `main-layout.php` (przycisk **Wyczyść cache** + globalne wyszukiwanie produktów/zamówień + sprawdzanie aktualizacji w menu)
1. **Double-submit (pusty koszyk + istnieje stare zamówienie)** — log: `Double-submit detected, redirecting to existing order id=...` ## Efekt
2. **Token nieprawidłowy** — log: `Token validation failed. formToken=...` - Przyciski aktualizacji systemu na `/admin/update/main_view/` działają.
3. **createFromBasket rzucił wyjątek** — log: `createFromBasket exception: ...` - Przycisk „Wyczyść cache" działa na tej (i każdej innej) podstronie admina.
4. **createFromBasket zwróciło falsy order_id** — log: `createFromBasket returned falsy order_id. client_id=... email=...` - Zdalny changelog ze `shoppro.project-dc.pl` nadal się wyświetla, ale nie może już popsuć struktury strony.
- Dodatkowy zysk bezpieczeństwa: zdalny serwis nie może wstrzyknąć JS w panel admina.
## Naprawa tokena — z jednorazowego na czasowy (TTL 30 min) ## Po wgraniu
1. Hard-reload przeglądarki (Ctrl+F5) — stary HTML siedzi w cache klienta.
### Stare zachowanie 2. Restart PHP-FPM / wyczyszczenie OPcache — inaczej stary skompilowany szablon dalej będzie serwowany.
- `createOrderSubmitToken()` generował nowy token przy KAŻDYM wejściu na podsumowanie
- Każde otwarcie nowej karty/odświeżenie nadpisywało token w sesji
- Formularz w starej karcie miał stary token → walidacja failowała
- Przy nieudanej walidacji tokena redirect na `/koszyk` (użytkownik tracił cały kontekst)
### Nowe zachowanie
- Dodana stała `ORDER_SUBMIT_TOKEN_TTL = 1800` (30 minut)
- Token przechowywany jako `['token' => '...', 'created_at' => time()]`
- `createOrderSubmitToken()`: jeśli istnieje ważny token (< 30 min), zwraca ten sam zamiast generować nowy
- `isValidOrderSubmitToken()`: sprawdza czy token nie wygasł + backward compatibility ze starymi stringowymi tokenami
- `consumeOrderSubmitToken()`: bez zmian — po złożeniu zamówienia token jest usuwany
- Przy nieudanej walidacji tokena redirect na `/koszyk-podsumowanie` (nowy token się generuje, użytkownik może od razu ponowić)
- Dodany osobny guard na double-submit: pusty koszyk + istniejące zamówienie w sesji → redirect na stronę zamówienia
### Efekt
- Wiele kart z podsumowaniem → ten sam token → wszystkie działają
- Przycisk "wstecz" → token nadal ważny
- Odświeżenie strony → token nadal ważny
- Po 30 minutach token wygasa → redirect na podsumowanie, nowy token, ponów
- Po złożeniu zamówienia token jest konsumowany + koszyk czyszczony → double-submit chroniony
- Błąd tokena nie wyrzuca na /koszyk tylko na /koszyk-podsumowanie