Rejtélyes ‘auto increment’ adatbázis probléma javítása

[Ezt a cikket 9 perc elolvasni.]

Egy igen különleges hiba megoldására kértek fel nemrégiben és néhány óra elteltével már majdnem úgy tűnt, hogy ki is fog fogni rajtam. Végül hosszas küzdelem után mégis meglett a megfejtés, ezután pedig elhatároztam, hogy egy cikk formájában dokumentálom a folyamatot, hogy ezzel segíthessek majd másokon, akik a jövőben ugyanezzel a problémával szembesülnek.

A jelenség a következő volt: Nem jelent meg a médiatár tartalma (folyamatos töltés jelzés, de zéró tartalom), valamint a fájlfeltöltés sem működött. A betallózott kép feltöltése minden esetben megállt a “Feldolgozás” (angolul Crunching) résznél mérettől és kiterjesztéstől függetlenül. A rutinos problémamegoldó rögtön rá is vágná, hogy itt bizony tulajdonosi/jogosultsági probléma van a könyvtárak körül, esetleg valamelyik bővítmény vagy éppen az aktív sablon zavarja össze a rendszer működését. Neki is láttam hát a diagnosztikának és minden elvégzett javítás után ismételten teszteltem a médiatárat és a képfeltöltést.

A következő lépéseket hajtottam végre:

  • Ellenőriztem a jogosultságokat => minden könyvtár 755, minden fájl 644
  • Bekapcsoltam a wp-debugot és engedélyeztem a logolást => semmi hibaüzenet
  • Az aktív sablont átváltottam egy alapértelmezett twenty* sablonra => a probléma továbbra is fenn állt
  • Az összes plugint inaktiváltam (egész egyszerűen ideiglenesen átneveztem a plugins mappát) => a probléma továbbra is fenn állt
  • Inaktiváltam a .htaccess-t => a probléma továbbra is fenn állt
  • Átnéztem a wp-config.php-t, hogy tartalmaz-e bármilyen utólagosan hozzáadott funkciót => nem tartalmazott
  • Újra feltöltöttem a wp-admin, wp-includes könyvtárakat és az összes WordPress core fájlt => a probléma továbbra is fenn állt
  • PHP verziót váltottam (5.6-ről 7.0-ra, majd 7.1-re) => a probléma továbbra is fenn állt
  • Aktiváltam az FTP-n keresztüli fájlműveleteket a wp-config.php-ban egy teszt erejéig => a probléma továbbra is fenn állt

A fenti lépések végrehajtása után kezdett valóban furcsává válni a dolog, ugyanis úgy tűnt, hogy a probléma minden mástól függetlenül van jelen, tehát sem a sablonok, sem a bővítmények, sem a .htaccess vagy éppen a PHP verziók nincsenek rá hatással. Közben rájöttem arra is, hogy a képfeltöltés valójában minden esetben végbemegy, tehát megjelenik a megfelelő év/hónap alatti mappában az általam feltöltött fájl, azonban itt elakad a folyamat és nem készülnek belőlük további méretek. Ekkor megpróbáltam kikapcsolni a funkciót, ami azért felelős, hogy további méreteket hozzon létre a rendszer, de természetesen ez sem vezetett eredményre.

A következő ötletem a böngésző fejlesztői konzoljának tanulmányozása volt (F12 / Hálózat fül). Nyitva hagytam az ablakot, megkíséreltem egy újabb fájl feltöltését és figyeltem az eredményt. Az async-upload.php sikeresen meghívásra került, majd utána jött is egy 403-as hibakód és egy meglepő válasz a szervertől a következő tartalommal: “The link you followed has expired.”, azaz “A követett hivatkozás érvényessége lejárt”.

A fenti üzenetre rákeresve elég sok találat érkezett, legtöbbször nagy méretű képek/bővítmények/sablonok esetén. A megoldás minden esetben az volt, hogy meg kellett emelni a PHP limitjeit (upload_max_filesize, post_max_size, max_execution_time). Éreztem, hogy ez az én esetemben nem fog segíteni, de természetesen megemeltem ezeket a paramétereket is. A feltöltési limitet 64M-ra, a maximum végrehajtási időt 300-ra és próbálkoztam még a memória limit megemelésével is 256MB-ra. Egyik sem hozott eredményt, a képfeltöltés továbbra sem működött és a konzolban ugyanúgy megjelent a 403-as hiba és a lejárt hivatkozással kapcsolatos üzenet.

Már majdnem kezdtem arra a konklúzióra jutni, hogy ez már csak szerver oldali hiba lehet, amikor eszembe jutott, hogy megpróbálok telepíteni egy teljesen szűz WordPress rendszert a tárhely egyik almappájába. Igazság szerint ettől sem reméltem sokat, mert az adatbázison kívül mindent kicseréltem és alaphelyzetbe állítottam a főoldal esetén is, de gondoltam egy próbát megér. A legnagyobb meglepetésemre itt tökéletesen működött a médiatár és a feltöltés is, tehát ki tudtam zárni a szerver oldali probléma lehetőségét is.

Mi maradt tehát az egyetlen dolog, amihez nem nyúltam eddig? Az adatbázis!

Nyitottam is egy PHPMyAdmin-t és elkezdtem nézelődni a táblák között. Minden core tábla a helyén volt, mindben ott volt a szükséges tartalom, tehát első látásra ez is jónak tűnt, azonban gyanús lett, hogy itt a táblák tartalmait nem engedte módosítani a rendszer míg a teszt célra létrehozott friss WordPress tábláit igen. Indítottam is egy javítást az összes táblára, de nem vezetett eredménye. Tehát nem összeomlott tábla okozza a gondot. A PHPMyAdmin által megjelenített üzenet szerint azért nem volt engedélyezett a szerkesztés, mert hiányzott a táblák struktúrájához beállított elsődleges kulcs (primary key). Próbáltam hát kézzel kiválasztani a megfelelő alapértelmezett azonosítókat, mint elsődleges kulcs, de mindig ugyanazt a hibaüzenetet kaptam: “Duplicate entry ‘0’ for key ‘primary'”. Tehát immáron biztossá vált, hogy adatbázis probléma van és ez lesz a rejtélyes hibánk forrása.

Hosszas olvasgatás után sem sikerült az adatbázist javítanom az interneten található megoldásokat követve, nulláról újraépíteni az oldalt pedig jelenleg nem volt opció, így hát drasztikusabb lépésre szántam el magam. Úgy döntöttem, hogy SQL lekérdezéseket futtatva végigmegyek a táblákon, törlök minden ID-t, aminek nulla az azonosítója, azután szintén lekérdezések formájában újra hozzárendelem az összes tábla struktúrájához a megfelelő elsődleges kulcsot, végül pedig engedélyezem hozzájuk az auto_incrementet, ami elengedhetetlen a rendszer normális működéséhez (ez a paraméter felel azért, hogy minden rekord beillesztésekor egyel nagyobb egyedi azonosítószámot kapjon maga a rekord és ne lehessen közöttük ebből fakadó ütközés).

A következő lekérdezések futtatása hajtotta végre a fenti feladatokat:

DELETE FROM wp_termmeta WHERE meta_id=0;
DELETE FROM wp_terms WHERE term_id=0;
DELETE FROM wp_term_taxonomy WHERE term_taxonomy_id=0;
DELETE FROM wp_commentmeta WHERE meta_id=0;
DELETE FROM wp_comments WHERE comment_ID=0;
DELETE FROM wp_links WHERE link_id=0;
DELETE FROM wp_options WHERE option_id=0;
DELETE FROM wp_postmeta WHERE meta_id=0;
DELETE FROM wp_users WHERE ID=0;
DELETE FROM wp_posts WHERE ID=0;
DELETE FROM wp_usermeta WHERE umeta_id=0;

ALTER TABLE wp_termmeta ADD PRIMARY KEY(meta_id);
ALTER TABLE wp_terms ADD PRIMARY KEY(term_id);
ALTER TABLE wp_term_taxonomy ADD PRIMARY KEY(term_taxonomy_id);
ALTER TABLE wp_commentmeta ADD PRIMARY KEY(meta_id);
ALTER TABLE wp_comments ADD PRIMARY KEY(comment_ID);
ALTER TABLE wp_links ADD PRIMARY KEY(link_id);
ALTER TABLE wp_options ADD PRIMARY KEY(option_id);
ALTER TABLE wp_postmeta ADD PRIMARY KEY(meta_id);
ALTER TABLE wp_users ADD PRIMARY KEY(ID);
ALTER TABLE wp_posts ADD PRIMARY KEY(ID);
ALTER TABLE wp_usermeta ADD PRIMARY KEY(umeta_id);

ALTER TABLE wp_termmeta CHANGE meta_id meta_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_terms CHANGE term_id term_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_term_taxonomy CHANGE term_taxonomy_id term_taxonomy_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_commentmeta CHANGE meta_id meta_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_comments CHANGE comment_ID comment_ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_links CHANGE link_id link_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT; ALTER TABLE wp_options CHANGE option_id option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_postmeta CHANGE meta_id meta_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_users CHANGE ID ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_posts CHANGE ID ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE wp_usermeta CHANGE umeta_id umeta_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;

Előfordulhat, hogy valamelyik fenti sor hibaüzenetet dob, ebben az esetben át kell ugrani és haladni kell tovább. Természetesen ezek futtathatók PHPMyAdmin-on keresztül is az “SQL” gombot megnyomva. Mondanom sem kell, hogy a fentiek futtatása előtt MINDEN esetben készíts biztonsági mentést a teljes adatbázisról, még akkor is, ha az hibás.

A fentiek elvégzése után izgatottan tesztelni is kezdtem a fájlfeltöltést és a médiatárat és nagy örömömre mind a kettő életre is kelt! A problémát tehát a hibás adatbázis struktúra okozta, mégpedig valószínűleg az auto_increment hiánya. Tippem szerint a weboldal adatbázisa nemrégiben kerülhetett importálásra, azonban a folyamat megszakadhatott mielőtt az export fájl végén található auto_increment lekérdezések futtatva lehettek volna. A másik lehetséges ok, hogy olyan módon lett exportálva az adatbázis, hogy ez nem tartalmazta az auto_increment szekciókat, emiatt a rendszer képtelen volt egy új fájl feltöltésekor egyedi azonosítót generálni a rekordnak.

A kutatás során több olyan külföldi fórumtémára bukkantam, ahol egy az egyben a fenti problémára kereste a választ a kérdező, azonban megoldás sajnos egyikre sem érkezett. Éppen ezért bízom benne, hogy másokon is segít majd az általam írt kis esettanulmány és lerövidíti majd a megfejtéshez szükséges időt.

Ha tetszik, mutasd meg másoknak is: