2026-10-23 16:06:29 +02:00
2026-10-23 16:06:29 +02:00
2025-05-24 23:00:30 +02:00
2026-10-23 15:26:08 +02:00
2026-10-23 15:26:08 +02:00
2026-10-23 16:06:29 +02:00
2026-10-23 16:06:29 +02:00
2026-10-23 16:06:29 +02:00
2026-10-23 16:06:29 +02:00
2026-10-23 15:26:08 +02:00

Drupal 6 – duże obrazy, lokalizacja tematów i bezpieczna optymalizacja

Rozbudowana wersja compare_filesize_drupal6. Działa poza Drupalem, w Pythonie 3.9+; potrzebuje dostępu do MySQL/MariaDB i katalogu plików.

Co robi

  • Wyszukuje największe pliki i największe rozdzielczości (JPG, PNG, GIF – GIF wyłącznie do analizy).
  • Wskazuje, w jakim temacie, poście lub komentarzu pojawia się obraz. Raport pokazuje nid, cid, tytuł, typ zawartości, URL do wpisu, URL do edycji i źródło powiązania.
  • Szuka połączeń przez upload.fid i pola *_fid w tabelach CCK/ImageField/FileField; obsługuje aktualne rewizje (vid) i opcjonalne tabele załączników komentarzy (cid + fid).
  • Szuka obrazów w node_revisions.body i node_revisions.teaser, comments.comment, opcjonalnie też w tekstowych polach CCK. Rozróżnia pewne dopasowania identyfikatora fid lub pełnej ścieżki od możliwych trafień po samej nazwie pliku.
  • Generuje link do oryginalnego pliku (jeżeli publiczny) i pomocniczy link do Drupal Search (jeżeli moduł Search jest aktywny).
  • Generuje CSV (polskie kolumny, Excel, UTF-8 BOM) i JSON.
  • Symuluje dokładną optymalizację w dry-run, bez zapisu źródłowego pliku i bazy.
  • Przy --apply zachowuje oryginał w oddzielnym katalogu, przygotowuje nowy obraz do atomowej podmiany, zapisuje files.filesize, a przy błędzie próbuje odtworzyć oryginał i wartości bazy.
  • Wykrywa duplikaty SHA-256 i pliki na dysku, których nie ma w analizowanym zestawieniu z bazy.

Instalacja

unzip compare_filesize_drupal6-extended.zip
cd compare_filesize_drupal6
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp config.example.py config.py

W config.py ustaw:

DB_CONFIG = {
    'host': 'localhost',
    'port': 3306,
    'database': 'drupal6_db',
    'user': 'drupal_user',
    'password': 'twoje_haslo',
    'charset': 'utf8',
}
FILES_BASE_PATH = '/var/www/drupal/sites/default/files'
PUBLIC_FILES_PATH = 'sites/default/files'
DRUPAL_ROOT = '/var/www/drupal'
DRUPAL_BASE_URL = 'https://forum.example.org'
DB_TABLE_PREFIX = ''

Ważne: FILES_BASE_PATH to lokalizacja rzeczywistych plików, a PUBLIC_FILES_PATH to fragment zapisany zwykle w files.filepath. Jeśli pliki są np. w /var/www/drupal/files, zmień obie wartości. Można też podać je w CLI: --public-files-path, --drupal-root. Gdy Drupal pracuje bez clean URLs, dodaj --no-clean-urls.

1. Znajdź tematy i komentarze z największymi obrazami

python main.py --find-usage --top 50 --report-csv najwieksze-z-linkami.csv

Przykładowe wiersze (fikcyjne):

  1.  18.42 MB  4200x5900  fid=1234  scans/mapa.jpg
      -> Archiwalne skany (forum, nid=812, pewne)
         LINK:   https://forum.example.org/node/812
         EDYCJA: https://forum.example.org/node/812/edit
         SKAD:   upload.fid, tresc wpisu (sciezka)
      -> Zdjęcie w komentarzu (forum, nid=920, cid=42, pewne)
         LINK:   https://forum.example.org/node/920#comment-42

CSV zawiera jedną linię dla każdego znalezionego miejsca. Gdy powiązania brak, w CSV zostaje plik, jego fid, rozmiar i propozycja wyszukiwania nazwą w Drupal Search.

Tylko skany lub wybrane pliki

python main.py --find-usage --top 100 --path-contains skan --report-csv skany.csv
python main.py --find-usage --fid 1234 --report-csv jeden-obraz.csv
python main.py --find-usage --min-size-mb 5 --usage-scope all --report-csv wieksze-niz-5mb.csv

--usage-scope top szuka tylko w --top N największych obrazach; optimizable – w obrazach przekraczających limity; all – w całym filtrowanym zestawieniu. Przy bardzo dużych bazach all może oznaczać długi skan treści. --no-text-scan wyłącza szukanie w treściach i zostawia szybsze powiązania fid. --scan-cck-text rozszerza skan na tekstowe pola CCK.

2. Dokładny dry-run optymalizacji

python main.py \
  --find-usage --usage-scope optimizable \
  --optimize --dry-run --optimize-top 20 \
  --max-width 2400 --max-height 3200 --max-file-mb 2 \
  --report-csv plan.csv --report-json plan.json

Dostaniesz rzeczywisty przewidywany rozmiar po rekompresji (test wykonany na pliku tymczasowym). Nie zmieni to oryginałów ani SQL. --top dotyczy wyświetlania; --optimize-top ogranicza liczbę obrazów poddawanych testowi/zmniejszaniu.

Duze skany: DecompressionBombWarning / DecompressionBombError

Pillow standardowo ostrzega powyzej ok. 89,5 mln pikseli (89,5 MP), a powyzej ok. 179 mln przerywa otwieranie z bledem DecompressionBombError. To limit liczby pikseli, nie rozmiaru pliku w MB. Uczciwe skany dokumentow moga miec 100-200 MP.

W tej wersji prog jest konfigurowalny: domyslnie --max-image-mpixels 220, dzieki czemu skany o 199 756 800 pikselach z podanego logu nie wywoluja juz ostrzezen ani automatycznego bledu Pillow. Narzedzie nie wylacza globalnie ochrony: otwiera naglowek, sprawdza liczbe pikseli przed dekodowaniem, a przekraczajace limit obrazy wypisuje jako [SKIP-LIMIT] z przyczyna. Pozostale rodzaje ostrzezen nie sa filtrowane. Zbyt duzy obraz nie zostaje zmieniony na dysku ani w bazie.

Uruchom ponownie swoj test:

python main.py \
  --min-size-mb 5 --optimize --dry-run \
  --max-width 4000 --max-height 6000 --max-file-mb 3 \
  --max-image-mpixels 220 --report-csv plan.csv

Jesli serwer ma malo RAM, mozna obnizyc limit, np. do --max-image-mpixels 120: obrazy powyzej 120 MP zostana pominiete, a nie bezwarunkowo dekodowane. Skany JPEG wymagajace skalowania korzystaja z draft() do zmniejszenia pamieci przy dekodowaniu. Bardzo duze PNG moga nadal potrzebowac ponad 1 GB RAM na dekodowanie i skalowanie; domyslny limit MP nie jest gwarancja bezpiecznego zuzycia pamieci. Uruchamiaj najpierw --dry-run, a --apply testuj na pojedynczych plikach z backupem.

Nie ustawiaj Image.MAX_IMAGE_PIXELS = None ani nie ignoruj wszystkich ostrzezen Pillow: takie ustawienia usuwaja mechanizm ostrzegania przed niebezpiecznymi obrazami.

3. Zmniejsz np. pierwsze 10 obrazów i aktualizuj bazę

Najpierw zrób pełen backup bazy danych i katalogu plików oraz przetestuj na kopii. Następnie:

python main.py \
  --optimize --apply \
  --optimize-top 10 --max-changes 10 \
  --backup-dir /srv/backups/drupal6-images \
  --max-width 2400 --max-height 3200 --max-file-mb 2 \
  --report-csv wykonane.csv --report-json wykonane.json

Każda udana zmiana:

  1. Zapisuje oryginał w osobnym katalogu (automatycznie tworzony podfolder uruchomienia).
  2. Zastępuje obraz tylko jeżeli nowy plik jest mniejszy o co najmniej --min-gain-percent (domyślnie 5%).
  3. Aktualizuje files.filesize dla wszystkich fid wskazujących na tę samą ścieżkę.
  4. W przypadku błędu SQL próbuje odtworzyć oryginalny plik i rozmiar w DB (także przy MyISAM – kompensacja aktualizacji).

--apply jest wymagane do każdego zapisu. Samo --optimize lub --update-db nie wykonuje zmian. Realna optymalizacja zawsze aktualizuje rozmiar w DB, także bez --update-db.

Jeżeli chcesz wyłącznie zsynchronizować rozmiary plików w istniejącym files:

python main.py --update-db --dry-run
python main.py --update-db --apply

--update-db w połączeniu z --optimize --apply dodatkowo koryguje rozmiary tych plików, które nie zostały zoptymalizowane.

Zasady jakości i bezpieczeństwa

  • JPEG: zachowuje rozszerzenie i ścieżkę, skaluje proporcjonalnie filtrem LANCZOS, zapisuje z wysoką jakością 92/89/86/85 (--jpeg-quality, --min-jpeg-quality). Nie schodzi poniżej skonfigurowanej jakości, nawet gdy cel 2 MB nie zostanie osiągnięty. JPEG jest formatem stratnym – każda ponowna kompresja może zmienić piksele.
  • PNG: zachowuje format oraz kanał przezroczystości, używa kompresji bezstratnej. Nie konwertuje PNG do JPEG i nie zmienia rozszerzeń, bo mogłoby to popsuć stare linki w Drupalu. Duży PNG ze skanem może pozostać duży, jeśli kompresja bezstratna nic nie da. Konwersja do JPEG wymagałaby osobnej, kontrolowanej migracji i aktualizacji odnośników.
  • Skan tekstowy: domyślny limit 2400 × 3200 px zamiast starego 1920 × 1080. Przed decyzją sprawdź czytelność drobnego druku w próbce i w razie potrzeby zwiększ limity lub pomiń plik.
  • GIF/animacje, nieobsługiwane formaty, niezgodności formatu i rozszerzenia: pomijane przy zapisie. Symlinki i hardlinki też są pomijane.
  • Kopia oryginału wymagana jest przy --optimize --apply, a lokalizacja kopii musi być poza FILES_BASE_PATH i poza katalogiem WWW Drupala (jeśli ustawiono DRUPAL_ROOT).
  • Weryfikacja czasu modyfikacji i inode chroni przed zmianą pliku w trakcie skanowania; zalecane jest wykonywanie pracy w oknie serwisowym.
  • Zachowuje ICC, DPI, EXIF (z prawidłową obsługą orientacji) i tekstowe metadane PNG w obsługiwanych formatach, ale nie gwarantuje zachowania każdego niestandardowego segmentu metadanych.
  • Aktualizowany jest tylko files.filesize – nie są zmieniane ścieżki, fid, treści postów ani załączniki. Zmiana dużego obrazka może wymagać ręcznego odświeżenia wygenerowanych miniatur przez ImageCache.
  • Kopia wykonana przez samo narzędzie obejmuje obraz, nie całą bazę. MyISAM nie zapewnia transakcji; procedura przywracania jest best-effort. Pełny backup DB i plików przed zmianami jest obowiązkowy.

Pozostałe opcje

python main.py --find-duplicates
python main.py --show-deleted --exclude-folders imagecache styles
python main.py --find-usage --no-clean-urls --site-url https://example.org/drupal
python main.py --help

Uwaga do --show-deleted: pokazuje pliki na dysku bez pasującego wpisu files w analizowanym zestawieniu, nie zaś potwierdzenie, że plik naprawdę nie występuje w treści. Przy filtrach (--path-contains, --min-size-mb, --fid) plik odfiltrowany może zostać pokazany jako „spoza zestawienia”. Nic nie jest usuwane.

Ograniczenia wyszukiwania

  • Powiązania po fid są najbardziej jednoznaczne; wyszukiwanie po samej nazwie pliku bywa niejednoznaczne – w raporcie pewnosc=mozliwe.
  • Tekst przeszukiwany jest w aktualnych rewizjach węzłów i komentarzach. Nie szuka w archiwalnych rewizjach ani w niestandardowych zewnętrznych modułach przechowywania treści bez włączonego skanu CCK.
  • Link do nieopublikowanego wpisu lub komentarza może wymagać konta z prawami administracyjnymi. Raport to zaznacza.
  • Drupal 6 stronicuje komentarze: node/NID#comment-CID może nie przewinąć do komentarza z dalszej strony. Jeżeli masz zainstalowany moduł Permalink dla Drupal 6, dodaj --comment-permalinks, aby generować comment/CID#comment-CID, które kieruje na właściwą stronę komentarzy. Bez tego modułu nie używaj tej flagi. Niezależnie od typu linku raport pokazuje nid i cid.
  • Nie ma gwarancji odnalezienia obrazów w niestandardowych relacjach tworzonych przez własne moduły, w CSS i w HTML poza bazą.
  • W przypadku prywatnego systemu plików adres bezpośredni do pliku może nie działać; odnośnik do tematu nadal powinien wskazać miejsce.

Testy

python -m unittest discover -s tests -v

Testy z lokalną, symulowaną bazą weryfikują powiązania Upload/CCK, obecne rewizje, komentarze, brak zmian w dry-run, aktualizację files.filesize, backup, przywracanie po błędzie SQL, format PNG i ścieżki katalogów. Nie zastępują próby na kopii konkretnej instalacji Drupal 6.

Źródła struktury bazy Drupal 6

S
Description
No description provided
Readme
97 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 100%