Bestehenden Webkatalog umziehen: Einträge, Kategorien und alte Adressen mitnehmen

Viele Webkataloge laufen noch mit Scripten aus den 2000er-Jahren. Die Einträge sind über Jahre gewachsen und von Hand geprüft, aber das Script bekommt keine Updates mehr, oder es läuft nach dem nächsten PHP-Update des Hosters nicht mehr. Wer dann umzieht, muss mehr retten als die Datenbank.

Ein Umzug ist vor allem eine Frage der Adressen. Die Einträge sind an einem Nachmittag übertragen. Ob Besucher, Suchmaschinen und die Websites, die auf Sie verlinken, den Katalog danach wiederfinden, entscheiden die Umleitungen.

Eines vorweg: Baut das neue System seine Adressen anders auf als das alte, bleiben Ihre alten Adressen nicht erhalten. Sie werden auf die neuen umgeleitet. Aus /Sport/Segeln/ wird dann zum Beispiel /segeln.html. Wer alle Adressen unverändert behalten will, muss beim alten System bleiben oder den Katalog einfrieren, siehe den nächsten Abschnitt.

Stand: 16.10.2026. Die SQL-Abfragen haben wir mit MySQL 8.0 und MariaDB 11.4 geprüft, Umleitungsregeln und Script mit Apache 2.4 und PHP 8.4 und 8.5. Tabellen, Spalten und Adressen der alten Scripte stammen aus deren Quelltexten. Andere Versionen weichen ab, sehen Sie in Ihrer eigenen Datenbank nach. Zeitangaben sind unsere Schätzungen.

  1. Muss es ein neues System sein?
  2. Bestandsaufnahme vor dem Umzug
  3. Daten aus dem alten Script holen
  4. Kategorien neu ordnen
  5. Umleitungen alter Adressen
  6. Einsender, Gegenlinks und Datenschutz
  7. Bezahlte Einträge
  8. Der Umzugstag
  9. Wie viel Arbeit das ist
  10. Umzug ins Verzeichnisscript

1. Muss es ein neues System sein?

Nicht jeder alte Katalog muss umziehen. Bevor Sie Einträge exportieren, lohnt der Blick auf alle Wege:

WegPasst, wennZu beachten
Altes Script für PHP 8 anpassen lassenFunktionen und Adressen sollen bleiben, wie sie sind.Bei alten Scripten betrifft die Anpassung oft viele Dateien. Danach pflegen Sie den Code allein, Updates des Herstellers gibt es nicht mehr.
Alte PHP-Version beim Hoster verlängernals Übergang für einige MonatePHP 5.6 bekommt seit Ende 2018 keine Sicherheitsupdates mehr. Das verschiebt das Problem nur.
Katalog einfrierenSie nehmen keine neuen Einträge mehr an, wollen den Bestand aber online lassen.Ein Werkzeug wie wget --mirror --adjust-extension --convert-links speichert alle Seiten als statisches HTML, das Formular entfällt. Lesbare Adressen bleiben erhalten. Adressen mit Parametern wie index.php?c=12 oder ?p=2 speichert wget als Dateien mit Fragezeichen im Namen, die der Server unter der alten Adresse nicht ausliefert. Dafür brauchen Sie eigene Umschreibregeln. Die Einträge veralten weiter, tote Links sollten Sie trotzdem einmal im Jahr entfernen.
Neuentwicklung desselben Herstellers, bei phpLD etwa PHPLD NextSie wollen bei Ihrem Anbieter bleiben.PHPLD Next ist laut Anbieter eine Neuentwicklung in einem frühen Stadium (Version 0.1.22, englisch). Ob der Umzug von phpLD 3 damit gelingt, prüfen Sie vorher. Mehr steht in der Übersicht der Verzeichnis-Scripte.
WordPress mit Verzeichnis-PluginIhre Website läuft ohnehin mit WordPress.Business Directory Plugin, Directorist und GeoDirectory bringen einen CSV-Import schon in der kostenlosen Version mit. Auch hier ändern sich die Adressen.
Eigenständiges Script, etwa das VerzeichnisscriptSie wollen ein schlankes System ohne WordPress und weiter Einsendungen annehmen.Die Adressen ändern sich. Wie viele Ebenen und welche Funktionen das neue System hat, prüfen Sie gegen Ihren Bestand.

Die übrigen Abschnitte gelten für die letzten drei Wege, bei denen Einträge in ein neues System wandern.

2. Bestandsaufnahme vor dem Umzug

Bevor Sie etwas exportieren, sichern Sie den alten Katalog vollständig: die Datenbank als SQL-Datei und alle Dateien per FTP. Diese Sicherung bleibt unangetastet, bis der neue Katalog seit Monaten läuft. Dann beantworten Sie vier Fragen:

  • Wie viele Einträge sind wirklich noch gut? Lassen Sie vor dem Umzug einen Linkprüfer über den alten Katalog laufen, etwa den W3C Link Checker. Jeder tote Link, den Sie jetzt löschen, ist einer weniger, den Sie übertragen, umleiten und später doch löschen.
  • Wie tief sind die Kategorien? Zählen Sie die Ebenen. Hat das neue System weniger, müssen Sie zusammenlegen, siehe Kategorien neu ordnen.
  • Welche Adressen werden besucht? In der Google Search Console zeigt der Leistungsbericht unter „Seiten“, welche Adressen Klicks bekommen. Die Zugriffsprotokolle des Servers zeigen auch Besucher, die nicht über Google kommen.
  • Auf welche Adressen verlinken andere? Der Bericht „Links“ in der Search Console nennt die am häufigsten verlinkten Seiten. Für diese Adressen muss die Umleitung auf jeden Fall stimmen.

Notieren Sie außerdem, wie die alten Adressen aufgebaut sind: Startseite, Kategorie, Unterkategorie, zweite Seite einer Kategorie, Seite eines einzelnen Eintrags, Suche. Rufen Sie dazu von jeder Art ein paar Seiten im Browser auf. Meist folgen die Adressen wenigen festen Mustern, und genau diese Muster brauchen Sie für die Umleitungen.

3. Daten aus dem alten Script holen

Fast jedes Katalogscript speichert Einträge und Kategorien in zwei Tabellen einer MySQL-Datenbank. Bei vielen Hostern erreichen Sie die Datenbank über phpMyAdmin. Dort führen Sie unter „SQL“ eine Abfrage aus, die Einträge und Kategorien zusammenführt, und exportieren das Ergebnis über „Exportieren“ als CSV. Setzen Sie dabei das Häkchen „Spaltennamen in die erste Zeile setzen“, denn der Import braucht die Kopfzeile. Leere Werte schreibt phpMyAdmin als NULL in die Datei. Der Import des Verzeichnisscripts liest das als leer, für andere Systeme tragen Sie unter „NULL ersetzen durch“ ein leeres Feld ein.

Nennen Sie die Spalten in der Abfrage gleich so, wie das neue System sie erwartet. Die Abfragen unten verwenden die Namen des Verzeichnisscripts. Exportieren Sie nur freigeschaltete Einträge. Wartende Einsendungen aus alten Katalogen sind oft jahrelang liegen geblieben und zum großen Teil Spam. Sehen Sie sie, wenn überhaupt, getrennt durch.

phpLinkDirectory (phpLD)

phpLD legt seine Tabellen mit dem Präfix PLD_ an, das in include/config.php steht. Die Einträge liegen in PLD_LINK, die Kategorien in PLD_CATEGORY. Für den Umzug wichtig sind diese Spalten, geprüft an den Versionen 2.1.2, 3.1.0 und 5.2.2:

TabelleSpaltenBedeutung
PLD_LINKTITLE, URL, DESCRIPTION, CATEGORY_IDder Eintrag und seine Kategorie
OWNER_NAME, OWNER_EMAILder Einsender
STATUS0 inaktiv, 1 wartend, 2 freigeschaltet
DATE_ADDEDDatum der Einsendung
RECPR_URLdie Adresse des Gegenlinks
FEATURED, LINK_TYPE, EXPIRY_DATEhervorgehobene und bezahlte Einträge mit Ablaufdatum. In 2.x und 3.x steht LINK_TYPE 4 für „featured“.
PLD_CATEGORYID, TITLE, TITLE_URL, PARENT_IDName, Adressteil und Elternkategorie, 0 bei der obersten Ebene
SYMBOLIC, SYMBOLIC_IDVerweise auf eine andere Kategorie, die Sie nicht übernehmen

Wie die alten Adressen aussehen, hängt davon ab, ob in phpLD lesbare Adressen eingeschaltet waren. Im Quelltext von phpLD 3.1.0 sind es diese Muster:

Seitemit lesbaren Adressenohne
Kategorie/Sport/Segeln/ aus den TITLE_URL der Kategorie und ihrer Eltern/index.php?c=12
zweite Seite einer Kategorie/Sport/Segeln/page-2.html/index.php?c=12&p=2
Seite eines Eintrags/detail/link-123.html/detail.php?id=123

Ist TITLE_URL leer, bildet phpLD 3.1 den Adressteil aus dem Titel und ersetzt dabei Sonderzeichen durch Unterstriche. Liegt der Katalog in einem Unterordner, steht dieser vor jeder Adresse. Vergleichen Sie die Muster deshalb mit einigen Seiten im Browser.

Die folgende Abfrage holt die Kategorie über bis zu vier Ebenen. Als kategorie nimmt sie die oberste Ebene, als unterkategorie die zweite. Tiefere Ebenen gehen in der zweiten auf, der vollständige alte Pfad steht zur Kontrolle in alter_pfad. Hervorgehoben ist ein Eintrag, wenn FEATURED gesetzt ist oder LINK_TYPE 4 ist.

SELECT l.TITLE AS titel, l.URL AS url, l.DESCRIPTION AS beschreibung,
       COALESCE(p3.TITLE, p2.TITLE, p1.TITLE, c.TITLE) AS kategorie,
       CASE WHEN p3.ID IS NOT NULL THEN p2.TITLE
            WHEN p2.ID IS NOT NULL THEN p1.TITLE
            WHEN p1.ID IS NOT NULL THEN c.TITLE
            ELSE '' END AS unterkategorie,
       CONCAT_WS(' > ', p3.TITLE, p2.TITLE, p1.TITLE, c.TITLE) AS alter_pfad,
       CONCAT('/', CONCAT_WS('/', p3.TITLE_URL, p2.TITLE_URL, p1.TITLE_URL, c.TITLE_URL), '/') AS alte_adresse,
       CONCAT('/detail/link-', l.ID, '.html') AS alte_eintragsadresse,
       l.OWNER_NAME AS name, l.OWNER_EMAIL AS email, 'ja' AS online,
       IF(l.FEATURED = 1 OR l.LINK_TYPE = 4, 'ja', 'nein') AS hervorgehoben,
       l.DATE_ADDED AS datum, l.EXPIRY_DATE AS ablauf
FROM PLD_LINK l
JOIN PLD_CATEGORY c ON c.ID = l.CATEGORY_ID
LEFT JOIN PLD_CATEGORY p1 ON p1.ID = c.PARENT_ID
LEFT JOIN PLD_CATEGORY p2 ON p2.ID = p1.PARENT_ID
LEFT JOIN PLD_CATEGORY p3 ON p3.ID = p2.PARENT_ID
WHERE l.STATUS = 2;

CONCAT_WS überspringt leere Ebenen, deshalb stimmt der Pfad bei einer, zwei, drei oder vier Ebenen. Waren lesbare Adressen ausgeschaltet, ersetzen Sie die beiden Adressspalten durch CONCAT('/index.php?c=', c.ID) und CONCAT('/detail.php?id=', l.ID). In Version 5 steht LINK_TYPE für eine eigene Tabelle der Eintragsarten, dort prüfen Sie die Werte vorher. Ab Version 5 kann ein Eintrag über PLD_ADDITIONAL_CATEGORY in weiteren Kategorien stehen, übernommen wird nur die Hauptkategorie.

Liefert diese Prüfabfrage Zeilen, hat Ihr Katalog mehr als vier Ebenen:

SELECT c.ID, c.TITLE FROM PLD_CATEGORY c
JOIN PLD_CATEGORY p1 ON p1.ID = c.PARENT_ID
JOIN PLD_CATEGORY p2 ON p2.ID = p1.PARENT_ID
JOIN PLD_CATEGORY p3 ON p3.ID = p2.PARENT_ID
WHERE p3.PARENT_ID <> 0;

Dann reicht ein weiteres LEFT JOIN nicht. COALESCE, CASE und beide CONCAT_WS müssen um die neue Ebene wachsen, sonst fehlt der Adresse das erste Stück und die Kategorie verrutscht, ohne dass eine Fehlermeldung kommt.

Kategorien ohne eigene Einträge, typisch für die oberste Ebene, tauchen in der ersten Abfrage nicht auf. Ihre alten Adressen brauchen trotzdem eine Umleitung. Diese Abfrage listet alle Kategorien mit Pfad und lässt symbolische Verweiskategorien weg:

SELECT CONCAT('/', CONCAT_WS('/', p3.TITLE_URL, p2.TITLE_URL, p1.TITLE_URL, c.TITLE_URL), '/') AS alte_adresse,
       CONCAT_WS(' > ', p3.TITLE, p2.TITLE, p1.TITLE, c.TITLE) AS alter_pfad
FROM PLD_CATEGORY c
LEFT JOIN PLD_CATEGORY p1 ON p1.ID = c.PARENT_ID
LEFT JOIN PLD_CATEGORY p2 ON p2.ID = p1.PARENT_ID
LEFT JOIN PLD_CATEGORY p3 ON p3.ID = p2.PARENT_ID
WHERE c.SYMBOLIC = 0
ORDER BY alter_pfad;

eSyndiCat

In der freien Version 1.7 und 1.8 heißen die Tabellen listings und categories, mit dem Präfix v17_ als Vorgabe. Der Status eines Eintrags ist active, approval (wartend) oder banned. Die Spalte path der Kategorie enthält den lesbaren Pfad mit Schrägstrichen, die Spalte level die Ebene. Die oberste Kategorie mit der Nummer 0 ist der Wurzelknoten und hat keine Einträge.

SELECT l.title AS titel, l.url AS url, l.description AS beschreibung,
       c.title AS kategorie, c.path AS alter_pfad, l.email AS email, 'ja' AS online,
       l.date AS datum, CONCAT('/', c.path, '/') AS alte_adresse
FROM v17_listings l
JOIN v17_categories c ON c.id = l.category_id
WHERE l.status = 'active';

Hier steht nur die Kategorie des Eintrags in der Datei. Die Zuordnung zu Haupt- und Unterkategorie ergänzen Sie in der Tabelle, siehe Kategorien neu ordnen. Die Spalte url fasst in eSyndiCat nur 100 Zeichen, längere Adressen sind dort schon gekürzt. Ältere Pro-Versionen bis 2.1 nennen die Tabelle der Einträge links statt listings. Für spätere Pro-Versionen haben wir das Schema nicht prüfen können.

Andere Scripte

Bei anderen Scripten sehen Sie in phpMyAdmin nach, welche Tabelle die meisten Zeilen hat und eine Spalte mit Webadressen enthält. Das ist fast immer die Tabelle der Einträge. Die Kategorien erkennen Sie an einer Spalte, die auf die eigene Tabelle verweist, oft parent_id oder parent.

Umlaute und Zeichensatz

Alte Scripte haben ihre Daten oft in Latin-1 gespeichert, manche auch doppelt kodiert. Dann steht „Designbüro“ statt „Designbüro“, oft nur in einem Teil der Einträge. Sehen Sie sich die CSV-Datei deshalb vor dem Import in einem Texteditor an, nicht nur in Excel. Der Import des Verzeichnisscripts erkennt doppelt kodierte Zeilen und repariert sie einzeln, korrekte Zeilen bleiben unverändert.

Wollen Sie schon in der alten Datenbank reparieren, ändern Sie nur die betroffenen Zeilen. Der binäre Vergleich in der Bedingung ist wichtig: Ohne ihn trifft LIKE '%Ã%' wegen der akzentunabhängigen Sortierung jedes „a“. Wir haben die Abfragen mit MySQL 8.0 und MariaDB 11.4 an Spalten in Latin-1 und UTF-8 geprüft. Arbeiten Sie trotzdem zuerst an einer Kopie:

-- Erst ansehen, welche Zeilen betroffen sind und was daraus würde
SELECT ID, DESCRIPTION, CONVERT(CAST(CONVERT(DESCRIPTION USING latin1) AS BINARY) USING utf8mb4) AS repariert
FROM PLD_LINK
WHERE CONVERT(DESCRIPTION USING utf8mb4) COLLATE utf8mb4_bin REGEXP 'Ã|Â|â€';

-- Dann nur diese Zeilen ändern
UPDATE PLD_LINK
SET DESCRIPTION = CONVERT(CAST(CONVERT(DESCRIPTION USING latin1) AS BINARY) USING utf8mb4)
WHERE CONVERT(DESCRIPTION USING utf8mb4) COLLATE utf8mb4_bin REGEXP 'Ã|Â|â€';

Steht in derselben Zeile außer den kaputten Umlauten ein Zeichen, das Windows-1252 nicht kennt, etwa „ł“, liefert MySQL NULL, und MariaDB bricht mit einem Fehler ab. Die erste Abfrage zeigt Ihnen solche Zeilen vorher. Das Werkzeug iconv -f UTF-8 -t WINDOWS-1252 taugt nur für Dateien, die durchgehend doppelt kodiert sind. Bei gemischten Dateien zerstört es die korrekten Zeilen.

4. Kategorien neu ordnen

Alte Kataloge haben oft drei, vier oder mehr Ebenen. Viele davon sind über die Jahre leer gelaufen oder enthalten nur einen Eintrag. Der Umzug ist die Gelegenheit, aufzuräumen.

Alter PfadNeue KategorieRegel
Freizeit › Sport › Segeln › JollenSport › SegelnDie dritte und vierte Ebene gehen in der zweiten auf. „Jollen“ kommt in die Beschreibung der Einträge.
Freizeit › Sport › Wintersport (2 Einträge)Sport › Weitere SportartenFast leere Kategorien zusammenlegen.
Freizeit (nur Unterkategorien)entfällt, Umleitung auf „Sport“Eine Ebene ohne eigene Einträge braucht es oft nicht.

Die Beispiele sind ausgedacht. Am einfachsten ordnen Sie in der CSV-Datei selbst: Ändern Sie die Spalten kategorie und unterkategorie mit Suchen und Ersetzen oder einer Formel. Die Spalten alte_adresse und alter_pfad lassen Sie stehen, sie sind die Quelle für die Umleitungen. Steht ein Eintrag im alten Katalog in mehreren Kategorien, entscheiden Sie sich für die, in der ihn die meisten suchen würden.

Heißen in verschiedenen Ästen mehrere Kategorien gleich, etwa „Sonstiges“, vergibt das Verzeichnisscript beim Anlegen Adressen wie sonstiges-2.html. Benennen Sie solche Kategorien vor dem Import lieber eindeutig, etwa „Sonstiger Sport“.

5. Umleitungen alter Adressen

Jede alte Adresse, die Besucher oder Links bekommt, braucht eine dauerhafte Umleitung mit dem Statuscode 301 auf die passende neue Seite. Google überträgt dann die Signale der alten Adresse auf die neue. Halten Sie die Umleitungen nach Googles Anleitung zum Website-Umzug „möglichst lange“ aufrecht, mindestens ein Jahr. Leiten Sie dabei nicht alles auf die Startseite um. Google kann solche Umleitungen als „Soft 404“ werten, also wie eine fehlende Seite. Haben Sie dagegen den Inhalt mehrerer alter Seiten auf einer neuen zusammengefasst, etwa die Seiten einzelner Einträge in ihrer Kategorie, ist die Umleitung dorthin in Ordnung.

Was beim Umzug aus den alten Adressen wird Fünf ausgedachte alte Adressen eines Katalogs nach dem Muster von phpLD 3 und ihr Ziel nach dem Umzug. Die Kategorie Sport, Segeln bekommt eine Umleitung mit Statuscode 301 auf die neue Kategorie segeln.html. Die Unterkategorie Jollen aus der dritten Ebene, die zweite Seite der Kategorie und die Seite eines einzelnen Eintrags bekommen ebenfalls eine 301-Umleitung auf dieselbe Kategorie. Ein gelöschter Eintrag ohne Nachfolger bekommt keine Umleitung, sondern den Statuscode 410. Darunter der Hinweis: nicht alles auf die Startseite umleiten. ALTE ADRESSE NEUES ZIEL /Sport/Segeln/ Kategorie /Sport/Segeln/Jollen/ dritte Ebene, zusammengelegt /Sport/Segeln/page-2.html zweite Seite der Kategorie /detail/link-11.html Seite eines Eintrags /detail/link-99.html gelöscht, kein Nachfolger 301 301 301 301 /segeln.html neue Kategorie 410 kein Ziel Nicht alles auf die Startseite umleiten. Muster wie bei phpLD 3.
Was aus den alten Adressen wird. Kategorien, Blätterseiten und Eintragsseiten bekommen eine Umleitung auf die neue Kategorie, Adressen ohne Gegenstück einen klaren Fehler.
Alte AdresseZielWoher die Zuordnung kommt
Kategorie und Unterkategoriedie neue Kategorie, in der die Einträge jetzt stehenSpalte alte_adresse
Kategorie ohne eigene Einträgedie neue Kategorie, die ihren Inhalt aufnimmtListe aller Kategorien, von Hand ergänzt
zweite und weitere Seite einer Kategoriedie erste Seite der neuen KategorieMuster der Blätterseiten
Seite eines einzelnen Eintragsdie Kategorie des Eintrags, wenn das neue System keine Eintragsseiten hatSpalte alte_eintragsadresse
gelöschter Eintrag ohne Nachfolgerkeine Umleitung, sondern Statuscode 410steht in keiner Liste
Suche, Formular, Admindie neue Suche oder das neue Formular, sonst 410einzelne Regeln

Rechnen Sie damit, dass Seiten einzelner Einträge, die bisher selbst bei Google standen, an Sichtbarkeit verlieren. Die Umleitung auf die Kategorie bewahrt die Links, nicht unbedingt die Platzierung.

Wenige Adressen: eine Regel je Adresse

Für einige Dutzend bis wenige Hundert Kategorien genügt je eine Zeile in der Datei .htaccess. Schreiben Sie sie als RewriteRule mit ^ und $. Dann trifft jede Regel genau eine Adresse, und die Reihenfolge spielt keine Rolle:

RewriteEngine On
RewriteRule ^Sport/Segeln/Jollen/$ /segeln.html [R=301,L]
RewriteRule ^Sport/Segeln/$ /segeln.html [R=301,L]
RewriteRule ^Freizeit/$ /sport.html [R=301,L]

Die Umleitungen gehören vor die Regeln des neuen Systems. Mischen Sie sie nicht mit Redirect-Zeilen. Redirect gehört zu einem anderen Apache-Modul, das unabhängig von den RewriteRule-Zeilen arbeitet. Außerdem trifft es alle Adressen, die mit dem Pfad beginnen, und hängt den Rest an das Ziel an. Redirect 301 /Sport/Segeln/ /segeln.html würde /Sport/Segeln/Jollen/ nach /segeln.htmlJollen/ schicken.

Viele Adressen: ein kleines Umleitungsscript

Bei Tausenden alten Adressen, etwa wenn jeder Eintrag eine eigene Seite hatte, wird die .htaccess unhandlich. Apache liest sie außerdem bei jedem Aufruf neu. Die Zuordnungstabelle RewriteMap wäre dafür gedacht, sie darf aber nur in der Serverkonfiguration stehen, nicht in der .htaccess. Das sehen Sie in der Apache-Dokumentation unter „Context“. Auf normalem Webspace nehmen Sie stattdessen ein kleines PHP-Script, das alte Adressen nachschlägt:

RewriteEngine On
# Alte lesbare Adressen: Kategorien, Blätterseiten, Eintragsseiten
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/(Freizeit|Sport|Reisen|detail)/
RewriteRule ^ umleitung.php [L]
# Alte Adressen ohne lesbare Pfade: index.php?c=12 und detail.php?id=123
RewriteCond %{QUERY_STRING} (^|&)c=[0-9]+
RewriteRule ^index\.php$ umleitung.php [L]
RewriteRule ^detail\.php$ umleitung.php [L]
<?php
// umleitung.php: alte Adressen in umleitungen.csv nachschlagen
// (alte_adresse;neue_adresse, eine Zeile je Adresse) und dauerhaft umleiten.

// Zweite und weitere Seiten einer Kategorie, bei phpLD 3 etwa /Sport/Segeln/page-2.html
const BLAETTERSEITE = '#page-[0-9]+\.html?/$#';

// Adressen mit Parametern bleiben, wie sie sind, Pfade enden einheitlich auf /
function schluessel(string $adresse): string
{
    return str_contains($adresse, '?') ? $adresse : rtrim($adresse, '/') . '/';
}

$liste = [];
if (($datei = fopen(__DIR__ . '/umleitungen.csv', 'r')) !== false) {
    while (($zeile = fgetcsv($datei, 0, ';', '"', '')) !== false) {
        if (count($zeile) >= 2) {
            $liste[schluessel($zeile[0])] = $zeile[1];
        }
    }
    fclose($datei);
}

$pfad = rawurldecode((string) parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH));
$abfrage = (string) ($_SERVER['QUERY_STRING'] ?? '');
$ziel = $abfrage !== '' ? ($liste[$pfad . '?' . $abfrage] ?? null) : null;
$ziel ??= $liste[schluessel($pfad)] ?? null;
if ($ziel === null && preg_match(BLAETTERSEITE, schluessel($pfad)) === 1) {
    // Blätterseite: auf die erste Seite der Kategorie umleiten
    $ziel = $liste[(string) preg_replace(BLAETTERSEITE, '', schluessel($pfad))] ?? null;
}
if ($ziel === null && preg_match('/(^|&)c=([0-9]+)/', $abfrage, $treffer) === 1) {
    // Blätterseite ohne lesbare Adresse, etwa index.php?c=12&p=2: nur die Kategorie zählt
    $ziel = $liste[$pfad . '?c=' . $treffer[2]] ?? null;
}

if ($ziel !== null) {
    header('Location: ' . $ziel, true, 301);
    exit;
}
// Nicht zugeordnet: im Fehlerprotokoll vermerken, damit Lücken in der Liste auffallen
error_log('Umleitung fehlt: ' . $pfad . ($abfrage !== '' ? '?' . $abfrage : ''));
http_response_code(410);
echo 'Diese Seite gibt es nicht mehr. Zum Katalog: <a href="/">Startseite</a>';

Die Regeln erfassen beide Arten alter Adressen von phpLD 3: lesbare Pfade und die Varianten mit Parametern. Ersetzen Sie in der dritten RewriteCond die Ordner durch die obersten Kategorien Ihres alten Katalogs, detail bleibt für die Eintragsseiten. So kommen nur alte Adressen beim Script an, auch wenn ein anderes System auf derselben Domain ebenfalls Adressen mit Schrägstrich am Ende hat, etwa WordPress. Die Regel für index.php?c=… greift nur, wenn der Parameter c dabei ist, die Startseite des neuen Systems bleibt also unberührt.

In umleitungen.csv stehen alte und neue Adressen, so wie der Import des Verzeichnisscripts sie liefert: Pfade wie /Sport/Segeln/ und Adressen mit Parametern wie /index.php?c=12. Blätterseiten leitet das Script auf die erste Seite der Kategorie um, bei Parametern zählt nur c. Jede alte Adresse, für die es keinen Eintrag findet, schreibt es mit „Umleitung fehlt“ ins Fehlerprotokoll von PHP. So sehen Sie Lücken in der Liste nach Tagen, nicht erst nach Wochen in der Search Console. Eine Liste mit 5.000 Zeilen liest PHP in wenigen Millisekunden. Bei sehr vielen Adressen legen Sie die Zuordnung besser in eine Datenbanktabelle mit Index.

Läuft Ihr Server nur mit nginx, gilt keine .htaccess. Die Umleitungen stehen dann in der Serverkonfiguration, für viele Adressen mit der Direktive map. Bei vielen Webspace-Angeboten arbeitet nginx allerdings vor einem Apache, dann gilt die .htaccess wie gewohnt.

Prüfen

Testen Sie nach dem Umzug eine Stichprobe alter Adressen, vor allem die aus der Bestandsaufnahme, die Klicks und Links bekommen. Mit curl -I https://www.ihr-katalog.de/Sport/Segeln/ sehen Sie den Statuscode und das Ziel. Danach zeigt Ihnen der Bericht „Seiten“ in der Search Console über Wochen, welche alten Adressen Google noch mit Fehler findet.

6. Einsender, Gegenlinks und Datenschutz

  • Nur übernehmen, was Sie brauchen. Viele alte Kataloge haben keine Einwilligung dokumentiert. Titel, Adresse und Beschreibung einer öffentlichen Website sind meist unproblematisch. Name und E-Mail der Einsender brauchen Sie dagegen oft nicht mehr. Übernehmen Sie sie nur, wenn Sie sie wirklich nutzen, etwa für Rückfragen bei toten Links (Grundsatz der Datenminimierung, Art. 5 Abs. 1 lit. c DSGVO).
  • Einsender sachlich informieren. Bleiben Sie Betreiber und dient das Verzeichnis demselben Zweck, brauchen Sie für den Umzug keine neue Einwilligung. Aktualisieren Sie aber die Datenschutzerklärung, wenn sich etwas ändert, etwa der Hoster. Eine Mail an die Einsender halten Sie rein sachlich: neue Adresse des Eintrags, Bitte um Korrektur falscher Angaben, Möglichkeit zur Löschung. Schon eine angehängte Bitte, die Zufriedenheit zu bewerten, hat der Bundesgerichtshof als Werbung gewertet (Urteil vom 10.07.2018, VI ZR 225/17).
  • Angebote nur mit Einwilligung. Wollen Sie den Einsendern bezahlte Einträge anbieten, ist das Werbung per E-Mail. Sie braucht eine vorherige ausdrückliche Einwilligung (§ 7 Abs. 2 Nr. 2 UWG). Die Ausnahme für Bestandskunden (§ 7 Abs. 3 UWG) gilt nur für Kunden, die schon gekauft haben, und nur, wenn Sie sie schon beim Erheben der Adresse auf ihr Widerspruchsrecht hingewiesen haben. In alten Katalogen ist das selten der Fall.
  • Alte Gegenlink-Pflicht. Viele alte Kataloge haben einen Gegenlink verlangt, phpLD etwa mit einem eigenen Feld dafür. Google wertet es in seinen Spam-Richtlinien als Link-Spam, wenn ein Link Bedingung ist und der andere ihn nicht kennzeichnen darf. Der Umzug ist ein guter Zeitpunkt, die Pflicht zu streichen. Die Gegenlink-Adressen müssen Sie nicht übernehmen.
  • Dienstleister. Lassen Sie den Umzug von einem Dienstleister machen, bekommt er Zugriff auf die Daten der Einsender. Dafür brauchen Sie mit ihm einen Vertrag zur Auftragsverarbeitung (Art. 28 DSGVO).

7. Bezahlte Einträge

Früher kauften Betreiber einen Eintrag vor allem wegen des Links und seiner Wirkung auf das Ranking. Das trägt nicht mehr. Google verlangt für bezahlte Links die Kennzeichnung rel="sponsored" oder rel="nofollow" (Ausgehende Links kennzeichnen). Seit 2019 behandelt Google diese Attribute als Hinweis, so gekennzeichneten Links folgt es nach eigener Aussage in der Regel nicht. Mit Linkkraft können Sie also nicht werben. Ein bezahlter Platz ist so viel wert wie die Besucher, die er bringt: oben in einer gut gepflegten Rubrik, die Menschen tatsächlich aufrufen.

  • Kennzeichnen. Neben dem Linkattribut verlangt das deutsche Recht, dass Werbung als solche erkennbar ist. Schreiben Sie sichtbar „Anzeige“ oder „bezahlter Eintrag“ dazu (§ 5a Abs. 4 UWG, § 22 Abs. 1 MStV). Im Verzeichnisscript steht die Kennzeichnung hervorgehobener Einträge anfangs auf „Empfehlung“. Stellen Sie sie vor dem Import unter Einstellungen › Anzeige auf „Anzeige“.
  • Reichweite belegen. Hängen Sie an die Adressen bezahlter Einträge einen Parameter wie ?utm_source=ihr-katalog an. Dann sieht der Kunde in seiner eigenen Statistik, wie viele Besucher Sie schicken. Das Verzeichnisscript zählt selbst keine Klicks.
  • Bestehende Kunden. Haben Einsender früher für einen normalen Link bezahlt, ändert sich mit der Kennzeichnung, was sie bekommen. Sagen Sie es ihnen, bevor Sie umstellen, und bieten Sie an, den Platz als Anzeige bis zum Ende der Laufzeit weiterzuführen oder den Rest anteilig zu erstatten. Sachliche Information zu einem laufenden Vertrag ist keine Werbung, ein neues Angebot schon.
  • Laufzeiten. Übernimmt das neue System keine Ablaufdaten, halten Sie sie in einer eigenen Liste fest. Die Abfrage oben schreibt sie in die Spalte ablauf. Läuft ein bezahlter Platz aus, nehmen Sie die Hervorhebung von Hand zurück.

8. Der Umzugstag

  1. Probelauf. Installieren Sie das neue System zuerst in einem Unterordner oder auf einer Subdomain, die Suchmaschinen nicht kennen, und schützen Sie sie mit einem Passwort. Ob dafür eine eigene Lizenz nötig ist, regeln die Lizenzbedingungen des neuen Systems. Unsere sagen, dass jede installierte Instanz eine Lizenz braucht. Für einen kurzen, geschützten Probelauf sprechen Sie uns bitte an. Importieren Sie dort und prüfen Sie Kategorien, Umlaute und eine Stichprobe von Einträgen.
  2. Formular schließen. Schließen Sie im alten Katalog das Eintragsformular einige Tage vorher. Einsendungen aus dieser Zeit müssten Sie sonst von Hand nachtragen.
  3. Umstellen. Neues System an die richtige Adresse, Import, Umleitungen aktivieren. Löschen Sie die alten Dateien noch nicht, verschieben Sie sie in einen geschützten Ordner.
  4. Prüfen. Stichprobe der alten Adressen mit curl -I, Formular testen, neue Sitemap in der Search Console einreichen. Die Adressänderung in der Search Console brauchen Sie nur, wenn sich die Domain ändert.
  5. Beobachten. Sehen Sie in den ersten Wochen jede Woche in den Bericht „Seiten“ und ergänzen Sie fehlende Umleitungen.

9. Wie viel Arbeit das ist

Unsere Schätzung für einen Katalog mit etwa 3.000 Einträgen in 150 Kategorien und drei bis vier Ebenen. Sie beruht auf unserer Arbeit an Verzeichnissen und ist nicht gemessen:

SchrittZeitbedarf (Schätzung)
Sicherung, Bestandsaufnahme, Linkprüfungzwei bis vier Stunden, dazu die Laufzeit des Linkprüfers
Abfragen anpassen und CSV exportierenein bis zwei Stunden
Kategorien zusammenlegenzwei bis sechs Stunden, je nach Tiefe
Probelauf mit Import und Kontrollezwei bis drei Stunden
Umleitungen anlegen und testenzwei bis vier Stunden
Beobachten in den ersten Wocheneine halbe Stunde je Woche

Zusammen sind das rund 9 bis 19 Stunden, also ein bis zweieinhalb Arbeitstage. Am meisten schwankt das Zusammenlegen der Kategorien. Es lohnt sich trotzdem, denn danach ist der Katalog übersichtlicher als vorher.

10. Umzug ins Verzeichnisscript

Wir verkaufen selbst ein Verzeichnis-Script, das Verzeichnisscript 2.1. Für einen Umzug bringt es mit:

  • einen CSV-Import im Admin, der Semikolon, Komma und Tab erkennt, Dateien in Windows-1252 nach UTF-8 umwandelt, doppelt kodierte Zeilen einzeln repariert und NULL aus phpMyAdmin als leer liest,
  • die Spalten der Abfragen oben: titel, url, beschreibung, kategorie, unterkategorie, name, email, online, hervorgehoben und datum. Englische Namen wie title, category und featured erkennt es ebenfalls, Adressen mit Umlauten im Domainnamen auch,
  • eine Vorschau vor dem Speichern und auf Wunsch das automatische Anlegen fehlender Kategorien,
  • die Spalten alte_adresse und alte_eintragsadresse: Nach dem Import bekommen Sie eine Liste alter und neuer Adressen als CSV, die direkt zum Umleitungsscript oben passt. Die Liste sammelt die Adressen aller Importe, auch über mehrere Anmeldungen, bis Sie sie leeren,
  • eine Sitemap unter /sitemap.xml für die Search Console und eine Linkprüfung, mit der Sie den übernommenen Bestand gleich nach dem Umzug kontrollieren.

Was es nicht kann: Es liest keine fremde Datenbank direkt ein, den Export als CSV machen Sie selbst. Eine Importdatei darf höchstens 2 MB groß sein, mit den Spalten der Abfrage oben sind das etwa 4.000 Einträge. Es hat zwei Kategorie-Ebenen und keine Seiten für einzelne Einträge, ein Eintrag steht in genau einer Kategorie. Laufzeiten, Zahlungen und Klicks bezahlter Einträge verwaltet es nicht. Hervorgehobene Einträge kennzeichnet es mit einem eigenen Text, den Link standardmäßig mit rel="sponsored".

Nach dem Kauf helfen wir 30 Tage per E-Mail und Telefon. Eine feste Zusage, wie lange Updates kommen und was sie kosten, steht bisher nicht in den Lizenzbedingungen. Fragen Sie uns vor dem Kauf, wenn das für Sie wichtig ist. Das Script ist offener PHP-Code ohne Verschlüsselung, und alle Einträge lassen sich als CSV exportieren. Sie können also jederzeit wieder umziehen. Wie der Import im Admin aussieht, zeigen die Screenshots. Den Umzug können Sie auch uns überlassen, zusammen mit der Installation. Den Preis dafür nennen wir nach einem Blick auf Ihren alten Katalog.

Weiterlesen: Eigenen Webkatalog oder Branchenverzeichnis erstellen mit den Abschnitten zu Regeln, Spam und toten Links, und die Übersicht der Verzeichnis-Scripte

Quellen: Google: Website-Umzug mit URL-Änderungen, Google: Weiterleitungen und die Google Suche, Google: Ausgehende Links kennzeichnen, Spam-Richtlinien der Google Suche, Apache-Dokumentation zu RewriteMap und Redirect, PHP: nicht mehr unterstützte Versionen, § 7 UWG, § 5a UWG, § 22 MStV, DSGVO, BGH, Urteil vom 10.07.2018, VI ZR 225/17 („Kundenzufriedenheitsbefragung“). Tabellen und Spalten von phpLD laut den Quelltexten der Versionen 2.1.2, 3.1.0 und 5.2.2, Adressmuster laut .htaccess, Vorlagen und include/functions.php von phpLD 3.1.0, von eSyndiCat laut eSyndiCat Free auf GitHub, geprüft am 16.10.2026.