<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="cs">
	<title>PHP triky</title>
	<subtitle>Weblog o elegantním programování v PHP pro mírně pokročilé</subtitle>
	<link rel="self" href="https://php.vrana.cz/atom.php"/>
	<!-- <link rel="search" type="application/opensearchdescription+xml" href="https://php.vrana.cz/opensearch.php"/> -->
	<link href="https://php.vrana.cz/"/>
	<id>https://php.vrana.cz/</id>
	<updated>2026-08-16T11:52:30+02:00</updated>
	<author><name>Jakub Vrána</name><uri>http://www.vrana.cz/</uri></author>
	<icon>https://php.vrana.cz/favicon.ico</icon>
	<logo>https://php.vrana.cz/logo.gif</logo>
	<rights>(c) 2005 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.</rights>
	<link rel="license" type="application/rdf+xml" href="http://creativecommons.org/licenses/by/2.5/rdf"/>
	
<entry>
	<title>Adminer 6.0.1</title>
	<link href='https://php.vrana.cz/adminer-6-0-1.php'/>
	<id>https://php.vrana.cz/:806</id>
	<updated>2026-08-16T11:52:30+02:00</updated>
	<published>2026-08-14T00:00:00+02:00</published>
	<category term='9' label="Adminer"/>
	<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>

<p>Všech změn je opět <a href="https://github.com/vrana/adminer/releases/tag/v6.0.1">velké množství</a>, popíšu jen ty nejzajímavější.</p>
<p><a href="https://www.adminer.org/"><b>Adminer</b></a> začínal s premisou „nahraj ho vedle dat a spusť“. Postupně se od ní ale začal vzdalovat. Verze <a href="adminer-4-6-3.php" class="inner">4.6.3</a> zakázala přihlášení bez hesla, verze <a href="adminer-6-0-0.php" class="inner">6.0.0</a> pak i případ, kdy ho uživatel zadá, ale server ho nevyžaduje. Řešení vždycky existovalo – nahrát plugin do adresáře a nakonfigurovat ho. Ale to je nad síly skupiny uživatelů, o které nechci přijít. Nová verze to proto zjednudušuje. Plugin pro přihlášení bez hesla je nově přímo součástí instalace jako <code class="language-php">Adminer\Password</code> a pokus o přihlášení bez hesla vypíše kód pro jeho konfiguraci.</p>
<p>Utratil jsem tokeny v hodnotě $700 na <a href="https://code.claude.com/docs/en/claude-security" target="_blank">bezpečnostní <em lang="en">scan</em></a> (naštěstí v rámci předplatného). Přinesl výsledky – našel menší bezpečnostní nedostatky v pluginech a chyby, které vyžadují značnou míru <em>social engineeringu</em>. Říkám jim <em lang="en">Self-<abbr title="Cross-site scripting" lang="en">XSS</abbr></em> – např. jste si nejprve museli vytvořit typ se speciálními znaky a při zobrazení jeho nápovědy došlo k chybě. Problém reálný, ale těžko zneužitelný.</p>
<p>Adminer šel odjakživa spustit ze zdrojových kódů. Vyžadoval ale pevnou strukturu podadresářů, takže nemohl běžet třeba na <code>http://localhost</code>, vždycky to muselo být aspoň <code>http://localhost/adminer/</code>. Teď jsem kód přeskupil tak, že stačí soubory v adresáři <code>adminer/</code> a adresář může být pojmenovaný libovolně.</p>
<p>Vylepšil jsem podle mě málo používanou stránku <a href="https://www.adminer.org/static/screenshots/schema.png">Schéma databáze</a>, která nově tabulky vykreslí do více sloupců podle jejich vazeb. Šipky můžou nově vést i zprava.</p>
<p>Vyhledávání dat ve všech tabulkách jsem vyřešil snad už pro všechny typy. Tady se nesmírně hodil robot – prostě si udělal matici TYP × OPERÁTOR × HODNOTA pro všechny ovladače a jel, dokud mu to celé neprošlo.</p>
<p>Na stránce editace jsem nechal vypsat dotaz, který záznam získal. Obdobný je už léta na výpisu dat.</p>
<p>Do importu jsem přidal ukazatel průběhu <em>uploadu</em>. Vypadalo to <a href="https://www.php.net/session.upload-progress">jednoduše</a>, ale zkomplikovalo se to kvůli tomu, že Adminer používá vlastní <code class="language-php">session_name()</code>, aby nekolidoval s ostatními stránkami.</p>
<p>Ovladač pro <a href="https://www.elastic.co/elasticsearch" target="_blank">Elasticsearch</a> nyní funguje i s <a href="https://opensearch.org/" target="_blank">OpenSearch</a>.</p>
<h3>Pluginy</h3>
<p>Zvýrazňovače syntaxe pro <a href="https://www.adminer.org/en/plugins/#driver">pluginy ovladačů</a> byly dřív přímo současí Admineru. Ale pak jsem přidal 5 kB klíčových slov pro Redis a přestalo se mi to líbit. Pluginy ovladačů si proto zvýrazňování syntaxe nově nesou v sobě.</p>
<p>Vytvořil jsem plugin jménem <a href="https://gist.github.com/vrana/2cf59635742c9a5d5873fca0bc6f168b">plugins</a>, který v UI informuje o pluginech, které jdou na daném místě použít. Jako okrajová záležitost je ale jen na Gistu.</p>
<h3>Interní změny</h3>
<ul>
<li>Kód nechávám kontrolovat i některými pravidly <a href="https://github.com/phpstan/phpstan-strict-rules" target="_blank">PHPStan strict</a> a <a href="https://github.com/slevomat/coding-standard" target="_blank">Slevomat Coding Standard</a>.</li>
<li>Adminer má slušné pokrytí <abbr title="End-to-End" lang="en">E2E</abbr> testy. Přidal jsem 5 dalších testů pro všechny ovladače, které pokrytí ještě zvýšily.</li>
<li>Testy jsem přidal i pro některé pluginy.</li>
</ul>
</div></content>
</entry>
<entry>
	<title>phpMyAdmin 6.0.0-dev</title>
	<link href='https://php.vrana.cz/phpmyadmin-6-0-0-dev.php'/>
	<id>https://php.vrana.cz/:805</id>
	<updated>2026-08-13T13:34:31+02:00</updated>
	<published>2026-08-08T00:00:00+02:00</published>
	<category term='9' label="Adminer"/>
	<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>

<p>Po letech jsem se podíval, jak pokročil <a href="https://www.adminer.org/cs/phpmyadmin/">phpMyAdmin</a> a je to snad ještě větší utrpení, než <a href="phpmyadmin-vs-adminer.php" class="inner">původně</a>:</p>
<ol>
<li>Přivítá mě hláškou o chybějícím rozšíření Sodium. Když na odkaz <a href="https://www.php.net/sodium">Sodium</a> kliknu, dostanu úplně tu stejnou chybovou hlášku, jen na jiném URL.</li>
<li>Do SQL příkazu vložím export databáze včetně <code class="language-sql">SET foreign_key_checks = 0</code> a skončí chybou. Musím ještě odškrtnout jejich <em lang="en">Enable foreign key checks</em>.</li>
<li>Když se import konečně provede, tabulky v menu nejsou aktualizované.</li>
<li>Kliknu na obnovit menu a celé menu poskočí tam a zpátky. To se mimochodem děje při načítání jakékoliv stránky. Vyrenderuje se o nějakých 50 pixelů vlevo a pak poskočí na správné místo.</li>
<li>Chci vytvořit tabulku – použiji odkaz v menu, který vygeneruje 4 sloupce. Pro přidání dalšího musím kliknout na tlačítko, které skončí chybou <em lang="en">Error code: 200. Error text: OK (rejected)</em>. Tabulku s více sloupci tedy můžu vytvořit jedině tak, že počet sloupců zadám předem v jiném formuláři.</li>
<li><em>Double-clickem</em> chci označit slovo ve výpisu, místo toho se začne editovat. Říkám si: „OK, rozbili mnou velmi často používané gesto pro označování po celých slovech, ale aspoň mají <em lang="en">inline</em> editaci.“ Změním hodnotu a kliknu vedle, abych změnil další. První změněná se bez jakéhokoliv mého potvrzení uloží a její editace zmizí. V Admineru můžu atomicky změnit víc hodnot najednou, klidně i v různých řádcích.</li>
<li>Ve výpisu zaškrtnu řádek a dám ho editovat. V prohlížeči se chci vrátit o stránku zpátky a nehodí mě to zpátky na výpis, ale na stránku, kde jsem byl předtím.</li>
</ol>
<p>Kdykoliv to po letech spustím, tak během pěti minut narazím na dlouhý seznam závažných chyb. A to se ani nesnažím chodit do nějakých hlubokých zákoutí, dělám naprosto běžné věci.</p>
<p>První načtení phpMyAdminu stáhne 40× víc dat než první načtení Admineru a každá další stránka taky 40× víc. Rychlost s tím jde ruku v ruce.</p>
<p>Další věc jsou 17 let staré bezpečnostní praktiky:</p>
<ul>
<li>Skrytí celého dokumentu a jeho zobrazení až JavaScriptem, pokud nejsem uvnitř rámu. Hlavičku <code class="language-http">X-Frame-Options</code> prohlížeče podporují od roku 2010.</li>
<li>Není důvod vnější odkazy přesměrovávat přes vlastní stránku, která <em lang="en">referrer</em> odstraní JavaScriptem. To je příčina té první chyby, na kterou jsem narazil. Atribut <code class="language-htm">&lt;a rel="noreferrer"></code> prohlížeče podporují od roku 2014.</li>
<li>Tajemství k <abbr title="Two-Factor Authentication" lang="en">2FA</abbr> je uložené přímo v databázi, ke které by mělo chránit přístup.</li>
</ul>
<p>„Výhoda“ phpMyAdminu je naprosto přeplácané uživatelské rozhraní. Např. phpMyAdmin má u každého řádku odkaz Smazat, na který můžu kliknout omylem a dialog bezmyšlenkovitě potvrdit. V Admineru musím řádek vybrat a tlačítkem jinde ho smazat. To je lepší nejen <abbr title="User interface" lang="en">UI</abbr>, ale i <abbr title="User experience" lang="en">UX</abbr>. Uživatelé mají pocit, že tam je strašně moc funkcí, přitom i celkem základní chybí (např. hromadné nastavení stejné hodnoty u více řádek).</p>
<p>Další „výhoda“ je nabubřelá instalace – 77 MB v 4891 souborech prostě nikdo ručně kopírovat nebude. Hostingy proto dávají phpMyAdmin předinstalovaný.</p>

</div></content>
</entry>
<entry>
	<title>Adminer 6.0.0</title>
	<link href='https://php.vrana.cz/adminer-6-0-0.php'/>
	<id>https://php.vrana.cz/:804</id>
	<updated>2026-08-14T17:17:05+02:00</updated>
	<published>2026-08-07T00:00:00+02:00</published>
	<category term='9' label="Adminer"/>
	<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>

<p>Začnu prosbou. Adminer má <a href="https://github.com/vrana/adminer/">na GitHubu</a> už jen o 400 ⭐ míň než <a href="https://adminer.org/cs/phpmyadmin/">phpMyAdmin</a>, kvůli jehož těžkopádnosti jsem začal na mrštné alternativně pracovat. Pokud vy nebo vaši známí Adminer používáte, dejte mu prosím hvězdičku.</p>
<p>Při vývoji Admineru jsem se dostal do totálního <em lang="en">flow</em>. Při řešení jedné věci mě napadly dvě další a <em lang="en">todo list</em> byl večer často dvakrát delší než ráno. <a href="https://www.adminer.org/"><b>Adminer</b></a> 6.0.0 obsahuje <a href="https://github.com/vrana/adminer/releases/tag/v6.0.0">více než 130 změn</a> a nebudu je tady všechny vypisovat. Vyberu jen to nejzajímavější:</p>

<h3>Bezpečnost</h3>
<p>Adminer už od verze <a href="adminer-4-6-3.php" class="inner">4.6.3</a> zakazuje přihlášení bez hesla. Hlavně uživatelům SQLite to komplikuje život. Pro ně jsem vytvořil <a href="https://www.adminer.org/cs/sqlite/">stránku</a>, kde si můžou stáhnout Adminer pro SQLite chráněný heslem dle jejich výběru.</p>
<p>Nově jsem zakázal i přihlášení k serverům, které se spokojí s jakýmkoliv heslem. <a href="https://www.adminer.org/cs/plugins/">Plugin</a> <kbd>login-password-less</kbd> na tyto změny reaguje a nově v něm lze použít stejné heslo pro SQLite jako máte třeba pro MySQL.</p>
<p>„Operátor“ SQL v Admineru používám třeba pro práci s JSON. Je ale samozřejmě nebezpečný, do SQL příkazu lze pomocí něj doplnit jakýkoliv kód. <code>SameSite</code> cookies používané Adminerem riziko snižují, ale doplnil jsem dvě další ochrany:</p>
<ul>
<li>Jeho použití vyžaduje poslání <code class="language-http">Sec-Fetch-Site: same-site</code> (<ins datetime="2026-08-14T17:00:00+02:00">nejde tedy spustit přímo z bookmarku</ins>).</li>
<li>V PostgreSQL se dotaz spustí jako <code class="language-pgsql">READ ONLY</code> a nelze spustit víc dotazů.</li>
</ul>

<h3>Vzhled</h3>
<p><img src="data/adminer-hover.png" width="321" height="235" alt="screenshot" class="right"> Chtěl jsem vypíchnout data v databázi a potlačit uživatelské rozhraní Admineru. Třeba skrytím opakujících se odkazů a jejich zobrazením až při najetí myši. Vzhled byl mnohem vzdušnější, ale zároveň vypadal děravý a na první pohled nebylo jasné, kde jakou funkci najdu. Částečná průhlednost rozhraní Admineru zase působila dojmem, že jsou odkazy <em lang="en">disabled</em>, tento experiment je k dispozici v <a href="https://www.adminer.org/cs/plugins/">pluginu</a> <kbd>menu-links</kbd> (volba <code>hover</code>). Nakonec jsem jen <em>checkboxy</em> a odkazy zobrazované v řádcích tabulky vystrčil mimo tabulku, s čímž jsem spokojen. Původní chování lze vrátit pomocí <a href="https://github.com/vrana/adminer/tree/main/designs/adminer-border">vlastního vzhledu</a>.</p>
<p>Přemýšlel jsem, jak se zbavit opakujících se odkazů <em>vypsat</em> v menu. Některé vzhledy je skrývají, jiné je vymění za ikonu. Ale já zhruba stejně často používám vypsání a strukturu tabulky a jakékoliv skrytí mě zmate. U ikony musím vždycky přemýšlet, jestli znamená to nebo ono, navíc vůbec není jasné, že by měla dělat něco jiného než odkaz z názvu tabulky. U explicitního <em>vypsat</em> přemýšlet nikdy nemusím.</p>
<p>Počet ošetřovaných znaků v URL jsem snížil na minimum. Z dřívějších ošklivých URL <code>where%5B0%5D%5Bcol%5D</code> je pěkně čitelné <code>where[0][col]</code>. Týká se to i formulářů, které nepředávají nevyplněná políčka, takže jsou URL mnohem kratší. Z této pro běžného uživatele neviditelné změny mám velkou radost.</p>
<p>Editační funkce bez parametru (např. <code class="language-sql">NOW()</code>) nově skryjí vstupní políčko. Zvažoval jsem to udělat i při výběru hodnoty <code class="language-sql">NULL</code>, ale tam mi vyhovuje, že stačí do vstupního políčka začít psát a <code class="language-sql">NULL</code> samo zmizí.</p>

<h3>Blbuvzdornost</h3>
<p>Adminer měl řadu kontrol konfigurace PHP, např. proti překročení <code class="language-phpini">max_input_vars</code> nebo <code class="language-phpini">upload_max_filesize</code>. Ty se ale provedly, až když bylo pozdě – po odeslání formuláře. Nyní se provádí už při jeho vyplňování.</p>
<p>Nové verze Admineru se pomocí <code class="language-htm">&lt;noscript>&lt;iframe sandbox></code> nově kontrolují i s vypnutým JavaScriptem. Kontrolu verzí jsem doplnil také k pluginům, pluginům ovladačů a vzhledům, které by měly být vždy ve stejné verzi jako Adminer. Nebyly k tomu potřeba žádné nové <em>requesty</em> – Adminer si s sebou prostě nese verze pluginů a vzhledů, které k němu pasují. Pokud jste si nějaký plugin vědomě změnili a kontrola vás otravuje, stačí přejmenovat jeho soubor. U vzhledů pak změnit první řádek v <code>adminer.css</code>.</p>

<h3>Import/export</h3>
<p>Export obecného SQL příkazu byl v některých případech problém. Mohl obsahovat proměnné nebo stavové informace, které při exportu chyběly. Vyřešil jsem to tak, že pokud to jde, použijí se pro export přímo data z vypsané tabulky, což je i rychlejší.</p>
<p>Import a export si dřív každý ovladač dělal po svém a obzvlášť v pluginech ovladačů to nefungovalo moc dobře. Teď jsem to sjednotil a ovladače si jen registrují své odlišnosti – např. pokud podporují <em lang="en">UPSERT</em>.</p>
<p>V PostgreSQL jsem problém s cizími klíči vyřešil tak, že se všechny <code class="language-pgsql">DROP TABLE</code> a <code class="language-pgsql">TRUNCATE</code> provedou na začátku.</p>

<h3>Pluginy</h3>
<ul>
<li>Od Davida Grudla jsem <a href="https://github.com/dg/adminer">převzal</a> plugin pro zobrazení varovného pruhu na produkčních serverech. (<kbd>remote-color</kbd>)</li>
<li>Vytvořil jsem plugin vyžadující přihlášení pomocí <a href="https://safety.google/safety/authentication/passkey/"><em lang="en">passkey</em></a>. (<kbd>login-passkey</kbd>)</li>
<li>Další plugin dovoluje importovat CSV soubory. To už Adminer dávno umí do strutury existujících tabulek, plugin dokáže strukturu tabulek odvodit z dat. (<kbd>import-csv</kbd>)</li>
<li><a href="https://www.adminer.org/editor/">Adminer Editor</a> defaultně zobrazuje obrázky, teď jsem tuto možnost dal i Admineru. (<kbd>select-image</kbd>)</li>
<li>Osm nepoužívaných pluginů jsem smazal.</li>
</ul>

<h3>Interní změny</h3>
<p>Z některých interních změn mám možná ještě větší radost než z toho, co je vidět navenek – hlavně z obsluhy JavaScriptových událostí.</p>
<table>
<tr><th>Dávno</th><td><code class="language-htm">&lt;a onclick="return aClick(this, 1, event);"></code></td></tr>
<tr><th>Od <a href="adminer-4-4-0.php" class="inner">4.4.0</a></th><td><code class="language-htm">&lt;a>&lt;script nonce="OGY1MDBkYjNhNGRmYjAwNWU5OGJjNjMwM2Q1Nzg1MWQ=">qsl('a').onclick = partial(aClick, 1);&lt;/script></code></td></tr>
<tr><th>Nově</th><td><code class="language-htm">&lt;a data-onclick='aClick(1)'></code></td></tr>
</table>
<p>Nový zápis je plně kompatibilní s <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP" target="_blank"><abbr title="Content Security Policy" lang="en">CSP</abbr></a> a neumožňuje přímé spuštění kódu. Je to jen přehledněji zapsané <abbr title="JavaScript Object Notation" lang="en">JSON</abbr> pole. Zjednodušilo to i obsluhu událostí v HTML kódu poslaného přes <abbr title="Asynchronous JavaScript and XML" lang="en">AJAX</abbr>, kterou druhý způsob přímo neumožňoval.</p>
<p>Pro závislosti Admineru používám <a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">Git submoduly</a>, které jsou pro mě mnohem pohodlnější než Composer. Ale pro lidi, co instinktivně píšou <code>git clone; composer i</code> jsem doplnil i podporu pro <code>composer i</code>. Nově to nainstaluje i <a href="https://eslint.org/">ESLint</a>, který se při <code>composer check</code> nyní spouští spolu s <a href="https://github.com/PHPCSStandards/PHP_CodeSniffer/">PHP_CS</a> a <a href="https://phpstan.org/">PHPStan</a>.</p>
<p><img src="data/adminer-size.svg" width="600" height="371" alt="graf" class="right"> Nechal jsem zjistit velikosti všech verzí Admineru. I přes velký nárůst funkčnosti nové verze se mi téměř podařilo zachovat velikost zkompilovaného souboru díky jednoduchému triku. Pro komprimaci překladů se používá komprimační tabulka angličtiny (funkce <code class="language-php">deflate_init</code>).</p>
<ul>
<li>V kořenovém adresáři už bylo moc souborů, proto jsem část z nich přesunul do podadresářů.</li>
<li>Maximální délku řádek jsem zkrátil z 250 na už celkem přijatelných 200 znaků.</li>
<li>Hlavní větev v Gitu jsem přejmenoval z <code>master</code> na <code>main</code>.</li>
<li>Sjednotil jsem úroveň požadovaného JavaScriptu. Některé obraty používaly zbytečně nové konstrukce, jiné zase zbytečně staré. Teď by měl fungovat jakýkoliv prohlížeč s podporou ES6, tedy kterýkoliv od roku 2018.</li>
<li><em lang="en">End-to-end</em> testy jsem přehodil z neudržovaného Katalonu na <em lang="en">headless</em> <a href="https://playwright.dev/" target="_blank">Playwright</a>.</li>
</ul>

<h3>Web</h3>
<p>Vyměnil jsem tabulky v <a href="https://demo.adminer.org/adminer.php">demu</a>. Demo nově funguje i s PostgreSQL.</p>

<h3>Závěr</h3>
<p>Většina změn vznikla s asistencí Claude Opus 5. Někteří lidi se bojí, že AI asistence může kód zamořit technickým dluhem. To je jistě pravda, pokud vývojář všechny změny bezduše odbouchne Enterem. Ale pokud si pořádně projde plán, vyjedná v něm změny a pak totéž udělá i s vygenerovaným kódem, kvalita kódu stoupne a technický dluh naopak klesne. Je to jako párové programování s pozorným kolegou – něco napadne mě, něco jeho a společně vzniklý kód je lepší, než kdyby ho kdokoliv z nás psal samostatně. Sám dělám při asistovaném vývoji odhadem tak dvakrát víc důležitých rozhodnutí, než když jsem na to sám.</p>

<!--
<p>V <a href="https://www.adminer.org/"><b>Admineru</b></a> jsem opravil nebo vylepšil spoustu věcí, které mě dlouho zlobily:</p>
<ul>
<li>Kontrola dostupnosti nové verze odjakživa vyžadovala JavaScript. Díky <code class="language-htm">&lt;noscript>&lt;iframe sandbox></code> nyní funguje i bez něj. S tím souvisí přidání metody <code>verifyVersion()</code>, kterou používá plugin <code>version-noverify</code>.</li>
<li>Zjištění údajů v přehledu tabulek (počet řádek, velikost indexů, …) trvá na MySQL dlouho, proto se nejprve vypíše jen seznam tabulek a údaje se pak dotáhnou na pozadí. V databázích, kde je zjištění údajů rychlé, se to teď dělá najednou, což zamezí probliknutí. Opravil jsem taky velikosti v MS SQL a Oracle a přidal alespoň celkovou velikost v SQLite. V SQLite se počet řádek zjišťoval prostým <code class="language-sqlite">SELECT COUNT(*)</code>, teď je rychlejší.</li>
<li>Ve výpisech se v bublině záhlaví sloupce zobrazuje jeho typ. Přidal jsem ho i do výsledku SQL příkazu.</li>
<li>V MS SQL a Oracle se v SQL příkazu nezobrazoval počet řádek tabulky.</li>
<li>Při exportu z SQL příkazu si <a href="https://sourceforge.net/p/adminer/bugs-and-features/760/" target="_blank">uživatelé</a> <a href="https://github.com/vrana/adminer/issues/1108" target="_blank">stěžovali</a>, že pokud napíšou třeba <code class="language-sql">SET @a = 1; SELECT @a</code>, tak se nevyexportuje nic. Adminer totiž při exportu znovu provede jen samotný příkaz, který vypsal data. Nejprve jsem zvažoval zachytávat a znovu provést příkazy <code class="language-sql">SET</code>, ale to by nevyřešilo třeba použití <code class="language-sql">LAST_INSERT_ID()</code>. Vzal jsem to za jiný konec – data se nově exportují JavaScriptem, což jednak vyřeší i <code class="language-sql">SELECT NOW()</code> a jednak to je rychlejší.</li>
<li>Při změně tabulky se nový sloupec už dlouho přidává JavaScriptem. Neplatilo to pro tlačítko v záhlaví tabulky, kam jsem to doplnil.</li>
<li>Při přesouvání sloupce ve změně tabulky se prosvěcovalo chytátko jiných sloupců.</li>
<li>V editaci mi chybělo ošetření sloupců obsahujících v názvu znaky <code>[]</code>.</li>
<li>Použití funkce SQL v editaci teď vždy zobrazí <code class="language-htm">&lt;input></code>, i když tam byl původně třeba <code class="language-htm">&lt;select></code>. (<a href="https://github.com/vrana/adminer/issues/1254" target="_blank">bug #1254</a>)</li>
<li>V editaci teď bezparametrové funkce jako <code class="language-sql">NOW()</code> nebo <code class="language-sql">UUID()</code> skryjí políčko s hodnotou.</li>
<li>V MS SQL se typ <code class="language-mssql">binary</code> bere jako blob. (<a href="https://sourceforge.net/p/adminer/bugs-and-features/369/" target="_blank">bug SF-369</a>)</li>
<li>V Elasticsearch a ClickHouse se použije výchozí port, pokud ho uživatel nezadal. V SimpleDB celý název serveru.</li>
</ul>
<h3>PostgreSQL</h3>
<ul>
<li>Podpora <a href="https://www.postgresql.org/docs/current/indexes-opclass.html"><em lang="en">operator classes</em></a>. Možností sloupců v indexech už bylo tolik, že jsem dal sloupce na samostatné řádky.</li>
<li>Ze seznamu rutin jsem odstranil ty přidané extenzemi.</li>
<li>Změna funkcí podporuje parametry typu pole a uživatelských typů.</li>
<li>Pokud ve výpisu použiji <code class="language-pgsql">COUNT(*), COUNT(DISTINCT id)</code>, tak Adminer jeden sloupec zahodil. To jsem teď opravil, týká se to i MS SQL.</li>
</ul>
<h3>Pluginy</h3>
<ul>
<li>V seznamu pluginů se teď zobrazují i ovladače.</li>
<li>Přidal jsem kontrolu verzí i pro pluginy, ale trochu jinak než pro samotný Adminer. U pluginů nejde o to, aby uživatelé používali jejich nejnovější verzi, ale tu kompatibilní s jejich verzí Admineru. Přemýšlel jsem, jak to nacpat do odpovědi z <a href="https://www.adminer.org/version/">adminer.org/version/</a>, ale pak jsem to udělal úplně jinak. Šlo mi hlavně o soukromí uživatelů, rozhodně jsem seznam nainstalovaných pluginů nechtěl někam posílat. Adminer má prostě uložené <code class="language-php">crc32</code> souborů s pluginy ve své verzi. Pokud se soubor liší, tak u něj Adminer zobrazí poznámku. Pokud si oficiální plugin změníte, stačí soubor přejmenovat a hláška zmizí.</li>
<li>Odstranil jsem nepoužívané pluginy <code>edit-calendar</code>, <code> tinymce</code>, <code> json-column</code>, <code> pretty-json-column</code>, <code> translation</code>, <code> email-table</code>, <code> dump-php</code>, <code> master-slave</code>.</li>
</ul>
<p>Také jsem modernizoval JavaScript, včetně <a href="https://jush.sourceforge.io/">JUSH</a>.</p>
-->


</div></content>
</entry>
<entry>
	<title>Adminer 5.5.1</title>
	<link href='https://php.vrana.cz/adminer-5-5-1.php'/>
	<id>https://php.vrana.cz/:803</id>
	<updated>2026-08-06T20:54:46+02:00</updated>
	<published>2026-07-21T00:00:00+02:00</published>
	<category term='9' label="Adminer"/>
	<content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>

<p><a href="https://www.anthropic.com/claude/fable">Claude Fable</a> jsem pustil i na závislosti <a href="https://www.adminer.org/"><b>Admineru</b></a>. Opravil řadu chyb v <a href="https://github.com/vrana/PhpShrink"><b>PhpShrink</b></a> a <a href="https://github.com/vrana/JsShrink"><b>JsShrink</b></a>. Admineru se netýkaly, ale i tak jsem za jejich opravu vděčný. Admineru se týká aktualizace zvýrazňování syntaxe v <a href="https://jush.sourceforge.io/"><b>JUSH</b></a>. Nechal jsem napsat i aktualizátory jazyků z oficiálních dokumentací.</p>
<p>Změny přímo v Admineru:</p>
<ul>
<li>Hlavička <code class="language-http">X-Forwarded-Prefix</code> se použila jen pro prefix <code>/[^/]</code>. Tomu bohužel vyhovuje i <code>/\evil.com</code>, což prohlížeče pořád vyhodnotí jako <code>https://evil.com</code>. (<a href="https://github.com/vrana/adminer/security/advisories/GHSA-fr74-9mf9-gf44">GHSA-fr74-9mf9-gf44</a>)</li>
<li>V přihlašovacím formuláři lze opět používat znaky <code>:/_</code>, které jsem v <a href="adminer-5-5-0.php" class="inner">minulé verzi</a> zakázal. (<a href="https://github.com/vrana/adminer/issues/1305" target="_blank">bug #1305</a>)</li>
<li>Kvůli minimalizaci velikosti byl zkompilovaný <code>adminer.php</code> binární soubor, s čímž uživatelé měli problém při všelijakém ručním kopírování (bug <a href="https://github.com/vrana/adminer/issues/1113" target="_blank">#1113</a>, <a href="https://github.com/vrana/adminer/issues/1213" target="_blank">#1213</a>). Jednoduchým řešením by bylo binární řetězce prohnat <code class="language-php">base64_encode</code>, jenže to je zvětší o 33 %. Hospodárnější řešení je každých 13 bitů binárního výstupu zakódovat jako dva znaky z rozsahu <code>[!-~]</code>, což přidá jen 23 %. Tady jsem si ověřil, jak moc modely pokročily – stejnou úlohu jsem zadal AI asi před půl rokem, dost jsem se s tím natrápil a výsledku jsem se stejně nedobral. Teď to bylo na první dobrou.</li>
<li>Toto navýšení jsem vyvážil změnou kompresního algoritmu z LZW na účinnější <code class="language-php">gzdeflate</code>. Pro dekompresi se používá <code class="language-php">gzinflate</code>. Jen pokud není k dispozici, tak se použije <a href="https://github.com/vrana/adminer/blob/master/adminer/include/decompress.inc.php">vlastní implementace</a> – to by se mi ručně fakt psát nechtělo.</li>
<li>Claude Fable jsem použil i na doplnění chybějících překladů, ale jen v případech, kdy si byla překladem jistá. Model k tomu využil i obraty ze stávajících překladů. Přeskočil jazyky, kterými si nebyl jist. Našel u toho i několik chyb v původních překladech. Nové překlady jsou označené komentářem <code class="language-php">// Claud Fable 5</code>, který můžou rodilí mluvčí po kontrole smazat. Doplnění překladů paradoxně snížilo velikost zkompilovaného souboru – každý jazyk se komprimuje zvlášť a místo chybějících překladů se používá angličtina. Míchání jazyků komprimaci zhoršuje.</li>
<li>Adminer v PHP 8 opět funguje i se zakázanou funkcí <code class="language-php">ini_set</code>. Starší verze PHP dokázaly funkce zakázané pomocí <code class="language-phpini">disable_functions</code> pořád zavolat, jen vyvolaly chybu, kterou Adminer potlačil. Od PHP 8 už takto zakázaná funkce nejde zavolat vůbec, proto jsem pro ni do Admineru musel přidat <em lang="en">wrapper</em>. Přidal jsem i kontrolu dostupnosti funkce <code class="language-php">set_time_limit</code>. (<a href="https://github.com/vrana/adminer/issues/1288" target="_blank">bug #1288</a>)</li>
<li>V PostgreSQL se jde opět přihlásit i s prázdným serverem. (<a href="https://github.com/vrana/adminer/issues/1304" target="_blank">bug #1304</a>, regrese z <a href="adminer-5-5-0.php" class="inner">5.5.0</a>)</li>
</ul>
<p>Také jsem aktualizoval <a href="https://github.com/PHPCSStandards/PHP_CodeSniffer/">PHPCS</a> a <a href="https://phpstan.org/">PHPStan</a>.</p>


</div></content>
</entry>

</feed>
