preg_replace & Co. im praktischen Einsatz

Ich bin immer noch an den exportierten Posts aus WordPress, die wir im Q&D-Editor schonmal manuell nachbearbeitet haben. Dabei sind sicher etliche Dinge aufgefallen, die man programmatisch korrigieren könnte, und wie man das praktisch angeht, schreib ich hier mal auf.

Wir haben immer noch die Ausgangstabelle rezepte, in der nur die ID, der post_content und der post_title drinstehen. Damit wir unsere Rohdaten nicht verhunzen, legen wir uns erstmal eine leere Kopie dieser Tabelle an, das geht im phpmyadmin unter „Operationen“, kopiere Tabelle, nur Struktur, oder mit dem simplen SQL:

CREATE TABLE rezepte_arbeit LIKE rezepte

Das kopiert die Struktur inklusive evtl. vorhandener Indizes etc. und wird unser Arbeitspferd. (Falls man mal die Daten mitkopieren möchte, CREATE TABLE table2 SELECT * FROM table1, aber das nur als Anmerkung am Rande)

Zur Kontrolle des Ergebnisses klemmt man sich die (noch leere) Arbeitstabelle in den Q&D-Editor. Spätestens jetzt macht es Sinn, den Namen der Tabelle auf eine Variable zu legen und die beiden SQLs entsprechend anzupassen.

//Arbeitstabelle festlegen
$arbeitstabelle = "arbeit_rezepte";
echo "<h1>Tabelle: ".$arbeitstabelle."</h1>";
...
$sql = "SELECT * FROM ".$arbeitstabelle." WHERE post_content LIKE '%".$filter."%'";
...
$sql = ('SELECT * FROM '.$arbeitstabelle.' WHERE post_content LIKE "%'.$filter.'%" 
LIMIT '.$limit.', '.$ergebnisse_pro_seite.'');

Wer es ganz genau haben möchte, legt auch noch den Dateinamen des Q&D-Editor Skripts auf eine Variable und paßt die Navigationslinks entsprechend an, aber das ist eigentlich schon Fleißarbeit:

//Dateinamen auf Variable legen
$datei = "arbeitspferd.php";
...
if($limit>0){echo '<a href="'.$datei.'?seite_nr='.($limit-1).'"><button type="button">Voriger Datensatz</button></a>';}
echo '<a href="'.$datei.'?seite_nr='.($limit+2).'"><button type="button">Nächster Datensatz</button></a><br>';
...
 //Nav Links alle Seiten
 for ($i=1; $i<=$row_total; $i++) { 
    echo "<a href='".$datei."?seite_nr=".$i."'>".$i."</a> "; 
};

Da die Tabelle noch leer ist, kriegt man erstmal gar nichts angezeigt:

arbeitstabelle_leer

arbeitstabelle_leer

Aber das ist ja OK so und wird sich gleich ändern.

Das Gerüst für die geplanten Aktionen

Ich bastle mir ein kleines Formular mit einem Button zum Starten des Skripts, und gebe der Übersicht halber mal alle Datensätze tabellarisch aus. Das sieht so aus:

<?php
//file:skript_starten.php
header('Content-Type: text/html; charset=utf-8');
require 'connection.php';

//Quell-und Zieltabelle festlegen
$quelltabelle = "rezepte";
$zieltabelle = "arbeit_rezepte";

echo "<h1>Skript starten</h1>";
echo "<h2> Quelle: ".$quelltabelle." Ziel: ".$zieltabelle."</h2>";

//Formular mit Button für Start
echo "<form action ='#' method = 'post'>";
echo "<input type = 'submit' name = 'absenden' value = 'Skript starten'>";
echo "</form>";

if(isset($_POST['absenden'])){
    
    echo "<script type=\"text/javascript\">alert('Skript gestartet');</script>";
    
    //Hier kommt die Action hin
    
    
    }

$sql = "SELECT * FROM ".$quelltabelle."";
$rs_result = $conn->query($sql);
$row_total = $rs_result->num_rows;

echo "Datensätze gesamt: ".$row_total."<br>";

 //Ausgabe in Tabelle - nur Arbeitsversion, kann man für den Betrieb rausnehmen
echo "<table border='1' cellpadding='4'>";
echo "<tr><th>ID</th><th>Titel</th><th>Content</th></tr>";
 
 while($row = $rs_result->fetch_assoc()) {
            
            echo "<tr><td valign='top'>".$row["ID"]."</td>";
            echo "<td valign='top'>".utf8_encode($row["post_title"])."</td>";
            //HTML Source in Textarea ausgeben
            echo "<td valign='top'><textarea rows='5' cols='80'>".utf8_encode($row["post_content"])."</textarea>";
            echo "</td></tr>";
            
 } //Ende von while row = rs_result
 
 echo "</table>";
 
?>

Ich hole mir mit dem require die Connection, lege Quell-Und Zieltabelle auf Variable und baue mir den Button für das Starten des Skripts. Die Kontrollausgabe der aktuellen Quelltabelle ist nicht unbedingt notwendig, das dient nur der Übersicht.

Jetzt gehts zur Sache

Der Ablauf ist folgender: die Datensätze aus der Quelltabelle werden selektiert und die Felder auf Variablen gelegt. An den Variablen nimmt man dann die nötigen Manipulationen vor, und die fertig bearbeiteten Datenfelder werden in ein Array geschrieben. Aus dem Array füllt man dann mit Insert die Zieltabelle. Das Ergebnis kann man dann gleich mal im Q&D-Editor überprüfen. Ich mach dann gleich noch ein Beispiel, hier zuerst mal der Source:

if(isset($_POST['absenden'])){
    
    echo "<script type=\"text/javascript\">alert('Skript gestartet');</script>";
    
    //Hier kommt die Action hin
    
    $sql = "SELECT * FROM ".$quelltabelle."";
    $rs_result = $conn->query($sql);
    
      
    $i=0;
    $temp = array();
    
    while($row = $rs_result->fetch_assoc()) {
            
            $akt_id =$row["ID"];
            $title = $row["post_title"];
            $content = $row["post_content"];
            
            // Hier kann man beliebige Stringfunktionen auf die Felder anwenden
            $content = strip_tags($content);
            
            //Behandelte Strings in Array einlesen
            $temp[$i][id] = $akt_id;
            $temp[$i][titel] = $title;
            $temp[$i][content]= $content;
            $i = $i+1;
            
    }
            
 }
$len_temp = count($temp);

//Array zeilenweise in Zieltabelle wegschreiben
for ($i = 0; $i < $len_temp; $i++){    
  
          $temp_id = $temp[$i][id];
          $temp_titel = $temp[$i][titel];
          $temp_content = $temp[$i][content];
          
          //addslashes ist nötig weil sonst der Insert bei jedem Hochkomma aussteigt
          $sql_insert = "INSERT INTO ".$zieltabelle." (ID, post_title, post_content) 
          VALUES (".$temp_id." ,'".addslashes($temp_titel)."' , '".addslashes($temp_content)."')";
          
          if (mysqli_query($conn, $sql_insert)) {
                      echo "Insert erfolgreich<br>";
                      
                    }
                      
                    else {
                      echo "Fehler beim Update: " . mysqli_error($conn);
                      
                    }
} // end for

Das wars schon – das Skript braucht ein paar Sekunden, nicht ungeduldig werden. Wichtig ist, dass man die einzufügenden Felder beim Insert noch mit einem addslashes() behandelt, weil sonst bei jedem Anführungszeichen im Text das Skript aussteigt.

Ich habe oben nur eine Ersetzung ausgeführt, nämlich das:

$content = strip_tags($content);

Das führt in der Praxis evtl. zu unerwünschten Effekten, weil es wirklich gnadenlos alle HTML-Tags raushaut. Für meine Zwecke besser geeignet ist der strip_tags mit Ausnahmen:

$content = strip_tags($content,'<h2>, <h3>, <ol>, <ul>, <li>');

Das läßt meine Überschriften und die Listen drin, sieht schon besser aus.

mit_liste

mit_liste

Aber da muss jeder selber tüfteln, was für seine Zwecke am besten geeignet ist. Fröhliches googlen nach praktikablen Stringbehandlungen! Und nicht vergessen vor erneutem Starten des Skripts die Zieltabelle mit Truncate zu leeren, sonst fällt der Insert wegen doppelter IDs auf die Nase.

Nachtrag: den Truncate kann man natürlich auch ins Skript mit einbauen, einfach die Action um folgenden Code ergänzen:

//Zieltabelle leeren
    $sql_zap="TRUNCATE TABLE ".$zieltabelle."";
    if (mysqli_query($conn, $sql_zap)) {
                      echo "Truncate erfolgreich<br>";
                      
                    }
                      
                    else {
                      echo "Fehler beim Truncate: " . mysqli_error($conn);
                      
                    }

Das muss natürlich vor dem Insert rein, am Besten setzt man es ganz an den Anfang innerhalb der if(isset($_POST…)-Bedingung. Dann spart man sich das manuelle Leeren der Zieltabelle.