PHP-Neuling: PHP: Session array erweitern -> Sortierfunktion im Index

0 47

PHP: Session array erweitern -> Sortierfunktion im Index

PHP-Neuling
  • datenbank
  • html
  • php
  1. 1
    localhorst
    • datenbank
    • javascript
    • php
    1. 0
      PHP-Neuling
    2. 0
      dedlfix
      1. 0
        localhorst
        1. 0
          1unitedpower
          1. 0
            localhorst
            • php
            • speicher
            1. 0
              1unitedpower
  2. 0
    dedlfix
    1. 0
      PHP-Neuling
      1. 0
        dedlfix
      2. 1

        Wichtig: Zuerst den Plan!

        Raketendiagnistiker
      3. 2
        TS
        • datenbank
        • https
        • php
  3. 0
    Rakketendiagnostiker
    1. 0
      dedlfix
      1. 0
        Raketendiagnostiker
    2. 0
      PHP-Neuling
      1. 0
        PHP-Neuling
      2. 1
        dedlfix
        1. 0
          PHP-Neuling
          1. 0
            dedlfix
            1. 0
              PHP-Neuling
              1. 0
                dedlfix
              2. 1
                localhorst
                • html
                • kontextwechsel
                • php
          2. 0
            Rolf B
            1. -1
              dedlfix
              1. 0
                Rolf B
              2. 1
                localhorst
                • datenbank
                • https
                • php
  4. 0
    vapita
    1. 0
      Matthias Apsel
  5. 0
    PHP-Neuling
  6. 0
    Felix Riesterer
    1. 0
      Raketenwilli
  7. 0
    Raketenheini
    1. 0
      PHP-Neuling
      1. 0
        localhorst
      2. -1
        Raketenheini
        1. 0
          localhorst
          • datenbank
          • https
          • php
        2. 0
          PHP-Neuling
          1. 0
            Felix Riesterer
            1. 0
              PHP-Neuling
              1. 0
                Felix Riesterer
                1. 0
                  PHP-Neuling
          2. 0
            vapita
            1. 0
              PHP-Neuling
      3. 0
        dedlfix
        1. 0
          Rolf B

Hallo Zusammen, ich versuche meiner Tabellenbasierten Datenbankübersicht (HTML, PHP) eine Sortierung zu verpassen.

In der Tabelle werden etliche Datenbankeinträge ausgelesen und dargestellt. Unter anderem werden Sachen wie "Standort", "Status", "Datum" etc. pp angeboten.

Im Tabellenkopf habe ich hierfür SELECT Boxen, welche über ein OnChange event direkt getriggert werden onchange="document.forms.showAK.submit()"

Im PHP Code gehts dann weiter mit IF (isset($_GET['showAK'] )) ... etc

Der SELECT dahinter befiehlt dann das sortieren nach dem ausgelesenen Wert von "showAK". Das funktioniert soweit.

Jetzt ist das aber total blöd, da ich nach dieser Logik nur nach einem Merkmal gleichzeitig sortieren kann. Ich möchte jetzt erreichen, dass sich die Seite "showAK" beispielsweise merkt, und ein zusätzliches "showOrt" noch mit dazunimmt, und im SELECT bearbeitet

Meine aktuellen Bemühungen sehen so aus :

$listing = array();
$_SESSION['listing'] = array();

IF (isset($_GET['showAK'] )) {	$ListAkademie = $_GET['showAK']; $listing[] = " KERN_AKADEMIE =  '$ListAkademie' "; }

$_SESSION['listing'] = $listing;
$multisort = implode(" AND ", $_SESSION['listing']);

$db->query("SELECT $Cols FROM DATABASE WHERE ($multisort) 

Die Idee dahinter war nun die, bei gesetztem Selectfeld (showAK etc...) den Wert aufzufangen (der Übersicht halber zunächst in eine temporäre Variable), und anschließend in ein Array zu packen, welches gleich den entsprechenden Teil des SELECT Befehls enthält.

Dies habe ich jetzt genau so wie oben für mehrere Spalten bzw. Selectfelder so geschrieben, sodass alle nötigen Werte zum Sortieren aufgefangen werden können.

Anschließend kommt das $array in ein $_SESSIONarray

Über ein Implode soll nun das notwendige "AND" zwischen die Werte des Arrays geschrieben werden.

Der abschließende SELECT Befehl verwendet nun die Variable "$multisort", die durch implode erstellt wird.

Grundlegend funktioniert das, aber nur einmal bzw. für eine Sortiermöglichkeit. Als würde die Session['listing'] jedes mal überschrieben werden. In der Variable steht immer nur ein Wert, sodass auch implode nie ein AND dazwischen bastelt.

Mit Session Arrays habe ich kaum Erfahrungen, bin mir aber sicher das ich hier etwas wichtiges nicht bedenke :(

Könnt ihr mir vielleicht, wieder, aushelfen? Eventuell ist mein Weg auch generell Käse und das ginge viel eleganter ?

Viele Grüße, und bleibt alle gesund

  1. Hallo,

    Deine Lösung sollte viel früher ansetzen.
    (an dieser Stelle setzen meistens schon einige Negativvoter ein, ...)

    Überlege, ob nicht bereits die Datenbankabfrage die richtige™ Lösung liefern könnte.

    Das hängt jedoch davon ab, ob (in M$-Speech) die originäre Abfrage ein Dynaset oder einen Snapshot darstellt, ob also Veränderungen am Datenbestand im Backend zwischen den einzelnen Darstellungen am Frontend dargestellt oder ignoriert werden sollen.

    Wenn sie ignoriert werden sollen, könnte man ebenfalls entweder mit einer Temporärtabelle im DBMS arbeiten, oder aber einer Kopie der Daten in der API, bei Dir also im PHP-Modul.

    Wenn Du die Sortierung im PHP-Modul vornehmen willst, dann wäre bei eindimensionaler Sortierung, bei der aber die Sortierspalte leicht umschaltbar bleiben soll, ein "Spaltenarray" anstelle eines satzorientierten (siehe Archiv, im Wiki leider unauffindbar) eine praktikable Lösung.

    Wenn allerdings nach mehreren Spalten sortiert werden soll, dann könnte man zwischen einer hinterlegten Sortierfunktion auf ein Satzarray ("Backreferenz"), oder einer redundanten Spalte, bestehend aus den Einzelsortierungen aus dem Spaltenarray, die dann ihrerseits sortiert wird, wählen. Für die Entscheidung sind die Datenmenge und die erforderlichen Sortierungen maßgeblich. Die generischen Sortierfunktionen in PHP sind um ein Vielfaches schneller (und bequemer anzuwenden), als eine per Backreferenz erstellte eigene Sortierfunktion. Außerdem benötigen die generischen Sortierfunktionen nebst "Spaltenarray" (erheblich) weniger Speicher.

    Erste Frage sollte also immer sein: Kann es nicht bereits das DBMS leisten?
    Zweite Frage könnte sein, wie lange die Sessiondaten für diese Views benutzt werden sollen.

    Die dritte Frage könnte sein, wieviel Mut man hat, gute (bitte immer im Einzelfall testen) kreative Lösungen gegenüber oft benutzten (häufig leider mit "best practise" bezeichneten) mangelhaft nachkalkulierten Lösungen vorzuziehen.

    Und nicht zu vergessen wäre die Möglichkeit, die Sortierung bei Irrelevanz für das Backend, überhaupt im Frontend mittes JavaScript vorzunehmen.

    LG +Gesundheit
    Localhorst

    1. Hi Localhorst,

      vielen Dank für deinen Beitrag.

      Was genau meinst du denn mit "generische Sortierfunktion" ? Inwiefern könnte mir das DBMS denn da helfen? Ich sortierte bisher stets über solche Abfragen und anschließendem aktuellen SELECT.

      Nicht, weil ich das als die beste lösung emfinde, eher weils die erste und beste war, die mir eingefallen ist. Wenn ich ohne neuen SELECT sortieren könnte, wäre das natürlich noch besser.

      Aber wie ?!

      Grüße

    2. Tach!

      Wenn Du die Sortierung im PHP-Modul vornehmen willst, dann wäre bei eindimensionaler Sortierung, bei der aber die Sortierspalte leicht umschaltbar bleiben soll, ein "Spaltenarray" anstelle eines satzorientierten (siehe Archiv, im Wiki leider unauffindbar) eine praktikable Lösung.

      Ich finde eine solche Lösung hingegen unpraktikabel, weil man dazu erst das zeilenbasierte Array umbauen muss.

      Und wenn man in PHP sortieren möchte, kommt man vom Regen in die Traufe. Die Daten aus dem DBMS müssen dann zwischen den Requests mit PHP-Mitteln gespeichert werden. Ob das einfacher ist, solch einen Mechanismus einzuziehen statt die schon vorhandene Datenbankabfrage zu erweite, habe ich meine Bedenken. Dazu muss ja auch noch eine Invalidisierung ausgedacht werden, sonst hängen die Daten ewig in der Session rum.

      Und nicht zu vergessen wäre die Möglichkeit, die Sortierung bei Irrelevanz für das Backend, überhaupt im Frontend mittes JavaScript vorzunehmen.

      Kann man machen, dazu müssen die Daten aber komplett im Client vorhanden sein und nicht nur seitenweise.

      dedlfix.

      1. Selber Tach! :-)

        Wenn Du die Sortierung im PHP-Modul vornehmen willst, dann wäre bei eindimensionaler Sortierung, bei der aber die Sortierspalte leicht umschaltbar bleiben soll, ein "Spaltenarray" anstelle eines satzorientierten (siehe Archiv, im Wiki leider unauffindbar) eine praktikable Lösung.

        Ich finde eine solche Lösung hingegen unpraktikabel, weil man dazu erst das zeilenbasierte Array umbauen muss.

        Man kann das gleich bei der Abfrage in die passende Form bringen. Dauert nicht messbar länger, aber spart <u>meistens</u> sogar merklich Speicherplatz. Und man kann anschließend sofort alle Spalten generisch sortieren. Je nachdem, welche man bei der anschließenden Iteration als Leitindex benutzt, liegen die Daten dann entsprechend sortiert vor.

        Es gab hierfür mal einen Artikel (von Dir?) unter PHP im Wiki, den ich mir damals sehr genau angesehen habe, und der mir schon oft geholfen hat, Flaschenhälse zu beseitigen. Die darin vorgestellten Funktionen waren/sind jedenfalls genial, universell verwendbar, und ich benutze sie bis heute!

        Und nicht zu vergessen wäre die Möglichkeit, die Sortierung bei Irrelevanz für das Backend, überhaupt im Frontend mittes JavaScript vorzunehmen.

        Kann man machen, dazu müssen die Daten aber komplett im Client vorhanden sein und nicht nur seitenweise.

        Kommt eben darauf an, um wieviel Daten es geht.

        LG + Gesundheit
        Localhorst

        1. Man kann das gleich bei der Abfrage in die passende Form bringen. Dauert nicht messbar länger, aber spart <u>meistens</u> sogar merklich Speicherplatz.

          Wie soll diese Einsparung zustande kommen? Möchte man eine Ergebnismenge mit n Zeilen und m Spalten in einem Zeilenarray speichern braucht man dafür n Array-Elemente, die ihrerseits jeweils ein Array der Länge m enthalten. Insgesamt liegt der Speicherbedarf also bei O(n*m). Möchte man in einem Spaltenarray speichern, dann braucht man m Arrays, die jeweils n Einträge enthalten. Der Speicherplatz liegt also bei O(m*n). Das ist Jacke wie Hose.

          Speicherbedarf einsparen könnte man unter gewissen Umständen, indem man direkt auf der Ergebnismenge arbeitet, dann ist ggf. nur ein Speicherverbrauch von O(m) notwendig, den man braucht um jeweils eine Zeile der Ergebnismenge in den Speicher zu laden.

          Davon abgesehen ist es müßig über Speicherplatz- und Laufzeit-Optimierungen zu reden, wenn es überhaupt kein diagnostiziertes Optimierungs-Potenzial gibt. Optimieren auf Verdacht verschlimmert die Situation eher. Erstmal gilt es unnötige Verrenkungen wie Spaltenarrays zu vermeiden und das Programm so leserlich wie möglich aufzuschreiben.

          Es gab hierfür mal einen Artikel (von Dir?) unter PHP im Wiki

          Ich glaube der Artikel war von Tom und hieß "Arrays mal anders herum". Er existiert inzwischen nicht mehr im Wiki, aber noch anderenorts im Internet.

          1. Hallo,

            Man kann das gleich bei der Abfrage in die passende Form bringen. Dauert nicht messbar länger, aber spart meistens sogar merklich Speicherplatz.

            Wie soll diese Einsparung zustande kommen? Möchte man eine Ergebnismenge mit n Zeilen und m Spalten in einem Zeilenarray speichern braucht man dafür n Array-Elemente, die ihrerseits jeweils ein Array der Länge m enthalten. Insgesamt liegt der Speicherbedarf also bei O(n*m). Möchte man in einem Spaltenarray speichern, dann braucht man m Arrays, die jeweils n Einträge enthalten. Der Speicherplatz liegt also bei O(m*n). Das ist Jacke wie Hose.

            Soweit die Theorie.
            Nur dumm, dass PHP hier gar keine klassischen statischen n*m-Arrays baut, sondern jedes Element irgendwo im Speicher ablegt. Verknüpft wird das dann über (Hash-)Listen mit Zeigern auf die eigentlichen Daten.

            Listen mit numerischen Indexwerten benötigen weniger Platz, als solche mit assoziativen Textschlüsseln. Und wenn man nun im Kopfknoten den Textschlüssel und in den Blattknoten nur den numerischen Indexwerte vermerken muss, spart das Platz gegenüber anders herum.

            Das kannst Du selber nachprüfen. Allerdings musst Du dafür eine ausreichende Anzahl von Testelementen produzieren, nicht nur drei...
            Der Speicher wird immer "portionweise" allokiert.

            Ich glaube der Artikel war von Tom und hieß "Arrays mal anders herum".

            Kann sein. Ich dachte, dass er von Dedlfix war. Darum habe ich wohl nichts mehr im Archiv gefunden. Ich habe mir damals nur die Funktionen gebunkert, weil die ganz praktisch sind.

            LG + Gesundheit
            Localhorst

            1. Soweit die Theorie.
              Nur dumm, dass PHP hier gar keine klassischen statischen n*m-Arrays baut, sondern jedes Element irgendwo im Speicher ablegt. Verknüpft wird das dann über (Hash-)Listen mit Zeigern auf die eigentlichen Daten.

              Das Kostenmodell ist nicht spezifisch für Arrays, es gilt genauso für Listen und andere Datenstrukturen, bei denen die Verwaltungskosten durch einen konstanten Faktor beschränkt sind.

              Listen mit numerischen Indexwerten benötigen weniger Platz, als solche mit assoziativen Textschlüsseln. Und wenn man nun im Kopfknoten den Textschlüssel und in den Blattknoten nur den numerischen Indexwerte vermerken muss, spart das Platz gegenüber anders herum.

              Das kannst Du selber nachprüfen. Allerdings musst Du dafür eine ausreichende Anzahl von Testelementen produzieren, nicht nur drei...

              Damit hast du natürlich vollkommen recht. Ich stelle trotzdem ein großes Fragezeichen vor die Effektivität einer solchen Maßnahme. Wenn Effizienz und Performance hohe Güter sind, dann sollte man damit auch ökonomisch umgehen. D.h. man misst erstmal, sucht die Optimierungspotenziale, erwägt mögliche Lösungen, schätzt die Entwicklungskosten ab und optimiert dann dort, wo die Kosten-Nutzen-Rechnung am günstigsten ist.

  2. Tach!

    ich versuche meiner Tabellenbasierten Datenbankübersicht (HTML, PHP) eine Sortierung zu verpassen.

    Dein Code zeigt aber keine Sortierung sondern das Zusammenbauen einer WHERE-Bedingung.

    (der Übersicht halber zunächst in eine temporäre Variable)

    IF (isset($_GET['showAK'] )) {	$ListAkademie = $_GET['showAK']; $listing[] = " KERN_AKADEMIE =  '$ListAkademie' "; }
    

    Ich weiß grad nicht, was daran übersichtlicher sein soll, statt ohne Zusatzvariable gleich den Wert zu verwenden. Was aber falsch ist: ihn ohne Maskierung zu verwenden. Das ist eine SQL-Injection-Lücke. Der Kontextwechsel muss immer beachtet werden.

    if (isset($_GET['showAK'] )) {
      $listing[] = sprintf(" KERN_AKADEMIE='%s' ", escape($_GET['showAK']));
    }
    

    Statt escape musst du das nehmen, das in deiner Datenbank-API vorgesehen ist. Vielleicht ist es das oder jenes.

    Der abschließende SELECT Befehl verwendet nun die Variable "$multisort", die durch implode erstellt wird.

    Als würde die Session['listing'] jedes mal überschrieben werden. In der Variable steht immer nur ein Wert, sodass auch implode nie ein AND dazwischen bastelt.

    Wenn Wunsch und Wirklichkeit nicht übereinstimmt, muss man debuggen. Gib dazu im einfachsten Fall die Werte der Variablen und Ergebnisse von Funktionsausfrufen mit var_dump() aus, und ermittle so, wo Abweichungen entstehen. (Ein <pre> davor auszugeben erhöht die Lesbarkeit.)

    Mit Session Arrays habe ich kaum Erfahrungen, bin mir aber sicher das ich hier etwas wichtiges nicht bedenke :(

    Vielleicht die Session nicht gestartet? Ein Indiz dafür wäre, wenn $_SESSION jedes Mal leer ist. Aber ohne zu wissen, was genau passiert, ist das nur der Versuch von Hellseherei.

    Eventuell ist mein Weg auch generell Käse und das ginge viel eleganter ?

    Es ist ein Anfang. Aber vielleicht wird der Wunsch aufkommen, die Sortierung in beide Richtungen vornehmen und auch wieder aufheben zu können.

    dedlfix.

    1. hi dedlfix

      das sichtbare ist "testcode". Über injections und sonstiges habe ich mir noch keine Gedanken gemacht. Ich wollte erst einmal erreichen, dass ich die Funktion hin bekomme und verstehe.

      "Übersicht" gilt für mich, damit ich während des Testbetriebs meinen eigenen geschriebenen Käse schritt für schritt besser nachvollziehen kann. Mir fällt es so leichter, mag aber sicher nicht jedem so gehen.

      Die SESSION läuft, da ich bereits andere Variablen in der SESSION habe bin ich auch sicher, dass dort alles funktioniert. Die SESSION[listing] ist ja auch nicht leer. Es steht aber eben nur ein Wert (der zuletzt gewählte).

      
      
      IF (isset($_GET['showAK'] )) {	$ListAkademie = $_GET['showAK']; $listing['AK'] = " KERN_AKADEMIE =  '$ListAkademie' "; }
      IF (isset($_GET['showOrt'] )) {	$ListOrt = $_GET['showOrt']; $listing['ORT'] = " KERN_DURCHFUEHRUNGSORT =  '$ListOrt' "; }
      IF (isset($_GET['showAbgabe'] )) { $ListAbgabe = $_GET['showAbgabe']; $listing['ABGABE'] = " KERN_ANGEBOTSABGABE = '$ListAbgabe' "; }
      IF (isset($_GET['showBindefrist'] )) {	$ListBindefrist = $_GET['showBindefrist']; $listing['FRIST'] = " KERN_BINDEFRIST = '$ListBindefrist' "; }
      IF (isset($_GET['showStatus'] )) {	$ListStatus = $_GET['showStatus']; $listing['STATUS'] = " KERN_STATUS = '$ListStatus' "; }
      IF (isset($_GET['showMassnahmeart'] )) { $ListMassnahmeart = $_GET['showMassnahmeart']; $listing['ART'] = " KERN_MASSNAHMEART = '$ListMassnahmeart' "; }
      
      //$_SESSION['listing'] = $listing;
      foreach ($listing as $key => $value) {
      $_SESSION['listing'][] = $value; }
      print_r($_SESSION['listing']);
      

      Es wird immer nur der letzte gewählte Wert ausgegeben über print_r. Der "alte" Wert ist dann weg :-/

      Grüße

      1. Tach!

        Es wird immer nur der letzte gewählte Wert ausgegeben über print_r. Der "alte" Wert ist dann weg :-/

        Mehr Debugging ist meine Empfehlung. Wenn du eine Datenstruktur ändern möchtest, und sie ist hinterher nicht so, wie sie sein soll, dann schau auch nach, ob sie vorher im erwarteten Zustand ist.

        dedlfix.

      2. IF (isset($_GET['showAK'] ))
        IF (isset($_GET['showOrt'] ))
        #...
        IF (isset($_GET['showMassnahmeart'] ))
        

        Das kann man bequem in einer Schleife machen. Die Spalten einer Tabelle bekommst Du in MySQL/MariaDB mit:

        SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '$shema' AND TABLE_NAME = '$table';
        

        kannst aber auch die Ausgaben von describe $shema.$table zerlegen. Das ist nur teurer. Oder Du notierst diese fix als Array.

        Wenn Du jetzt mit z.B. mit $_GET['showAK'] eine -1, 0 oder eine 1 als Wert sendest, dann kannst Du einstellen, ob die Spalte (jetzt, künftig) angezeigt werden soll, (jetzt, künftig) nicht mehr angezeigt werden soll.

        Das kannst Du auch mit 'showAK' machen -> 'sortAK':

        • 1 : aufsteigend,
        • 0 : nicht sortieren/Sortierung aufheben
        • -1 : absteigend

        Die Keys baue aus 'sort' + originalen Spaltenname (siehe Abfrage oben).

        Wenn Du kombinierte Sortierungen benötigst brauchst Du noch eine Liste, z.B. in $_GET['sortOrder'] welche die Reihenfolge vorgibt. Sonst ist das Ergebnis zufällig.

        Und vor allem brauchst Du zuerst einen Plan.

      3. Hello,

        vergiss bei der ganzen Testerei mit isset() nicht das Festlegen der Defaults für die Parameter, für den Fall, dass es welche geben soll.

        Glück Auf
        Tom vom Berg

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.
  3. Jetzt ist das aber total blöd, da ich nach dieser Logik nur nach einem Merkmal gleichzeitig sortieren kann.

    1. So lange, wie da
    $listing = array();
    $_SESSION['listing'] = array();
    #...
    $_SESSION['listing'] = $listing;
    

    notiert ist wird das auch so bleiben.

    Einfache Logik: Wenn Du zu einem Array ein Item hinzufügen willst, dann darfst Du den Array vorher nicht leeren. Ist doch klar: Wenn Du einen Korb mit einem Apfel hast und eine Birne hinzufügen willst, dann darfst Du den Korb vorher nicht ausschütten…

    1. Räume Deinen Code mal auf. Wenn man schon sprechende Variablennamen verwendet, dann sollte auch drin sein, was drauf steht:
    $db->query("SELECT $Cols FROM DATABASE WHERE ($multisort) 
    
    • In $multisort stehen aber Deine where-Clauseln.
    • Da, wo DATABASE steht soll wohl entweder die Tabelle oder Datenbank.Tabelle stehen.

    Mit sowas schießt man sich selbst das Gehirn ab und macht dann Fehler.

    1. Das die Prüfung/Behandlung der an die Datenbank übergebenen Strings fehlt und dass das gefährlich ist, wurde Dir schon mitgeteilt. Prüfe also gegen beabsichtigte Spaltennamen gegen die reellen Spaltennamen und maskiere die Werte mit der für Deine Verbindung geeigneten Methode, z.B. mysql_real_escape_string().
    1. Tach!

      [...] maskiere die Werte mit der für Deine Verbindung geeigneten Methode, z.B. mysql_real_escape_string().

      Diese Funktion ist schon lange nicht mehr geeignet und auch in keiner der noch gepflegten PHP-Versionen mehr enthalten.

      dedlfix.

      1. Tach!

        [...] maskiere die Werte mit der für Deine Verbindung geeigneten Methode, z.B. mysql_real_escape_string().

        Diese Funktion ist schon lange nicht mehr geeignet und auch in keiner der noch gepflegten PHP-Versionen mehr enthalten.

        Wie ich schon über die falschen Benennungen schrieb:

        Mit sowas schießt man sich selbst das Gehirn ab und macht dann Fehler.

        (Du hast also recht.)

    2. Hi Raketentyp,

      und Danke für deine Ausführungen.

      Äh, Richtig. in $multisort wird die SQL Ausführung gespeichert. DATEBASE ist nur ein Platzhalter. In echt steht da natürlich der Name meiner Datenbank.

      Mir war tatsächlich nicht bewusst, dass die array zuweisung von $listing die Variable gleich wieder leert. Ich nahm irgendwie an, php "merkt" sich das.

      Nun habe ich diese Zuweisungen x = array(); entfernt, und siehe da

      array(3) { [0]=> array(1) { ["AK"]=> string(27) " KERN_AKADEMIE = 'Aachen' " } [1]=> array(1) { ["STATUS"]=> string(24) " KERN_STATUS = 'Zusage' " } [2]=> array(1) { ["AK"]=> string(27) " KERN_AKADEMIE = 'Berlin' " } }                 
      

      Nun funktioniert das. Boah. Manchmal ... Naja

      Okay aber das ist ja schon mal gut. Nun müsste ich nur noch erreichen, dass die multidimensionalen Werte bei Änderungen überschrieben werden. ["AK"] beispielsweise darf es im SELECT natürlich nur einmal geben

      1. okay, wenn ich die dimension festschreibe, funktioniert das nun auch

        ...

        Der entsprechende Key wird bei Neuwahl ersetzt. Super :)

        Das scheint also erstmal hinzuhauen. Nur wird jetzt nicht mehr selected. Entsprechend bleibt die Ausgabe leer

        EDIT:

        Habe die Anführungszeichen für die Werte vergessen. Jetzt geht es :-D

        IF (isset($_GET['showAK'] )) {	$_SESSION['listing'][0]['AK'] = "KERN_AKADEMIE = " . "'" . $_GET['showAK'] . "'"; }
        
      2. Tach!

        Mir war tatsächlich nicht bewusst, dass die array zuweisung von $listing die Variable gleich wieder leert. Ich nahm irgendwie an, php "merkt" sich das.

        Das wäre unlogisch und eine programmiertechnische Katastrophe, wenn eine Zuweisung mal etwas zuweist, aber ein anderes Mal etwas ergänzt. Sowas muss schon eindeutig bleiben.

        array(3) { [0]=> array(1) { ["AK"]=> string(27) " KERN_AKADEMIE = 'Aachen' " } [1]=> array(1) { ["STATUS"]=> string(24) " KERN_STATUS = 'Zusage' " } [2]=> array(1) { ["AK"]=> string(27) " KERN_AKADEMIE = 'Berlin' " } }                 
        

        Gib ein <pre> vorher aus. So eine Zeichenwurst ist doch nur schwer zu verstehen. Und dann wäre es auch günstig, wenn du in diesem Forum deinen Code nicht generell als HTML auszeichenen würdest, egal was es ist.

        Nun müsste ich nur noch erreichen, dass die multidimensionalen Werte bei Änderungen überschrieben werden. ["AK"] beispielsweise darf es im SELECT natürlich nur einmal geben

        Nur zu. Noch ein Tipp. Ein Problem hat die besten Chancen verstanden zu werden, wenn der Code dazu vollständig und nachvollziehbar ist. Das heißt nicht, dass du dein gesamtes Programm veröffentlichen sollst, sondern es auf den für das Problem relevanten Teil kürzt. So ein Minimalfall-Beispiel hilft auch dir selbst beim Herausfinden der Ursache, wenn dabei alles Unwichtige (oder alles angeblich Unwichtige) nicht mehr vom Kern ablenkt.

        dedlfix.

        1. Tach dedl,

          ich habe nun Erfolg! Auch mit recht Übersichtlichem und knappen Code

          IF (isset($_GET['showAK'] )) {	$_SESSION['listing'][0]['AK'] = "KERN_AKADEMIE = " . "'" . $_GET['showAK'] . "'"; }
          
          
          $multisort = implode(" AND ",$_SESSION['listing'][0]); 
          
          
          

          So funktioniert es einwandfrei. Bei Neuwahl der selben Selectbox (bspw. ShowAK) wird überschrieben.

          TipTop :)

          Ich danke euch allen vielmals für eure Ideen und Hinweise. Jetzt geht's ans aufräumen und absichern und fehler ausmerzen :)

          Grüße

          1. Tach!

            Auch mit recht Übersichtlichem und knappen Code

            Oft geht es besser.

            IF (isset($_GET['showAK'] )) {	$_SESSION['listing'][0]['AK'] = "KERN_AKADEMIE = " . "'" . $_GET['showAK'] . "'"; }
            
            
            $multisort = implode(" AND ",$_SESSION['listing'][0]); 
            

            So funktioniert es einwandfrei. Bei Neuwahl der selben Selectbox (bspw. ShowAK) wird überschrieben.

            Und wie wird dem Nutzer angezeigt, welche Felder (und vielleicht die Reihenfolge) für die Sortierung verwendet werden? Ich meine, wie merkst du dir diese Angaben zwischen den Requests, um daraufhin den HTML-Code entsprechend zu beeinflussen? Wobei … das was du machst ist ja keine Sortierung sondern eine Filterung. Auch da möchte der Anwender sicher sehen, wonach gefiltert wurde.

            Du merkst dir gerade fertige (abgesehen vom SQL-Injection-Problem) SQL-Schnipsel. Diese sind für andere Zwecke wenig brauchbar. Besser wäre es, die Rohdaten aufzuheben, und den Mechanismus für das Zusammenstellen des SQL-Statements separat zu programmieren.

            Wenn du nun anfängst das SQL-Injection-Problem zu beheben, musst du das in allen Zeilen wiederholen. Auch wenn du Änderungen oder Ergänzungen am SQL-Code vornehmen möchtest, musst du das in allen Zeilen einbauen. Trenne lieber Verarbeitung der Rohdaten und die Logik, die nur für die Ausgabe relevant ist. Das EVA-Prinzip kann man auch im Kleinen anwenden. Damit wird dann zwar deine implode-Zeile etwas aufweniger, du entschlackst dafür aber die obigen Zeilen.

            dedlfix.

            1. Hi die Anzeige geschieht über die Selectfelder im Kopf der Tabelle. Hier wird der aktuell gewählte Wert angezeigt (echo $_GET...)

              Klar würde ich deinem Rat gerne folgen, aber ich weiß nicht wie? Ich weiß leider nicht, was du meinst?

              Trenne lieber Verarbeitung der Rohdaten und die Logik, die nur für die Ausgabe relevant ist. Das EVA-Prinzip kann man auch im Kleinen anwenden. Damit wird dann zwar deine implode-Zeile etwas aufweniger, du entschlackst dafür aber die obigen Zeilen.

              1. Tach!

                Klar würde ich deinem Rat gerne folgen, aber ich weiß nicht wie? Ich weiß leider nicht, was du meinst?

                Speicher in der Session nur Feldname und Suchwert. Das ist ein einfaches Array mit Key-Value-Paaren, zumindest beim Filtern. Beim Sortieren schreibt man in das Value die Sortierrichtung (asc/desc).

                Das Statement zusammenzubauen erfolgt dann in zwei Schritten. Der erste geht in einer Schleife über die gemerkten Felder und ihrer Werte und baut die Teilbedingungen zusammen, der zweite implodiert wie schon gehabt:

                $conditions = [];
                foreach ($pairs as $key => $value) {
                  $conditions[] = sprintf("%s='%s'", $key, escape($value));
                }
                $condition = implode(' AND ', $conditions);
                

                Das "escape" steht hier wieder als Platzhalter für die konkrete Funktion deiner Datenbank-API.

                dedlfix.

              2. Hallo,

                die Anzeige geschieht über die Selectfelder im Kopf der Tabelle. Hier wird der aktuell gewählte Wert angezeigt (echo $_GET...)

                hoffentlich
                echo htmlspecialchars($_GET[•••], ENT_QUOTES, 'UTF-8' )
                oder ähnlich

                LG + Gesundheit
                Localhorst

          2. Hallo PHP-Neuling,

            ich sehe den Thread gerade erst und habe noch nicht so ganz durchgeblickt. Aber dieses [0] hinter $_SESSION['listing'] kommt mir schon merkwürdig vor. Warum ist das ein Array?

            Mit scheint auch, dass Du es Dir sehr kompliziert machst. Jeder Filter steckt in seinem eigenen Form? Warum machst Du nicht ein Form, wo alle Filter drin sind? Dann musst Du Dich gar nicht damit herumschlagen, was zuvor eingestellt war, du sammelst einfach alles ein, was Du an Parametern bekommst. Allerdings hast Du dann auch die SELECT-Boxen in der Eingabe, wo nichts ausgewählt ist, d.h. Du musst nicht mit isset abfragen, sondern darauf, ob der Parameter einen Leerstring enthält.

            $filterWerte = ARRAY();
            IF (!empty($_GET['showAK'])) {
               $filterWerte[] = "KERN_AKADEMIE = '" . $db->escape($_GET['showAK']) . "'";
            }
            IF (!empty($_GET['showOrt'])) {
               $filterWerte[] = "KERN_DURCHFUEHRUNGSORT = '" . $db->escape($_GET['showOrt']) . "'";
            }
            ...
            $filter = IMPLODE(' AND ', $filterWerte);
            

            sollte korrekt ein Array aus WHERE Bedingungen erstellen. Ich persönlich würde die ganzen ifs noch in einer Funktion kapseln, und String Parsing statt Verkettung nehmen. Das geht so:

            function addWhereCondition(@$conditions, $parameterName, $dbColumn, $db) {
               if (!empty($_GET[$parameterName])) {
                  $value = mysqli_real_escape_string($db, $_GET[$parameterName]);
                  $conditions[] = "$dbColumn = '$value'";
              //  $conditions[] = "$dbColumn = '{$db->escape_string($_GET[$parameterName])}'";
               }
            }
            

            Edit: !empty statt isset eingebaut

            Die auskommentierte Zeile kann die beiden Zeilen davor ersetzen. Es muss aber ein Methodenaufruf auf einem Objekt sein. Einfach nur ein Funktionsaufruf wie mysqli_excape_string ist auch in der complex syntax nicht möglich.

            Das Parameterparsing sieht dann so aus:

            $filterWerte = ARRAY()
            addWhereCondition($filterWerte, 'showAK', 'KERN_AKADEMIE', $db);
            addWhereCondition($filterWerte, 'showOrt', 'KERN_DURCHFUEHRUNGSORT', $db);
            addWhereCondition($filterWerte, 'showAbgabe', 'KERN_ANGEBOTSABGABE', $db);
            addWhereCondition($filterWerte, 'showBindefrist', 'KERN_BINDEFRIST', $db);
            addWhereCondition($filterWerte, 'showStatus', 'KERN_STATUS', $db);
            addWhereCondition($filterWerte, 'showMassnahmeart', 'KERN_MASSNAHMEART', $db);
            
            $multisort = implode(" AND ", $filterWerte); 
            

            Ist doch deutlich übersichtlicher, oder? Kein Session-Eintrag mehr nötig, das merkt sich jetzt der Client. Beim Erzeugen der Ausgabeseite musst Du natürlich dafür sorgen, dass die ausgewählten Filterwerte für die SELECTs auch voreingestellt werden (über die selected-Eigenschaft am <option> Element).

            Ob sich jetzt noch dedlfixens Idee lohnt, Rohdaten und Erzeugung der WHERE-Bedingung zu trennen? Ich weiß nicht. Denn die Rohdaten hast Du ja im $_GET Array. Wenn es für einen anderen Zweck sinnvoll ist, die Filterparameter in einer Datenstruktur beisammen zu haben, dann könnte man das nochmal überlegen. Dann könnte man eine Objektklasse FilterParameter machen, sie mit den $_GET-Parametern initialisieren und eine Methode "createSQL" hinzufügen, die die WHERE-Bedingung erzeugt.

            Damit erledigt sich dann auch die Frage, wie man eine einzelne Bedingung wieder entfernt. Einfach eine Leer-Option einstellen.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Tach!

              Allerdings hast Du dann auch die SELECT-Boxen in der Eingabe, wo nichts ausgewählt ist, d.h. Du musst nicht mit isset abfragen, sondern darauf, ob der Parameter einen Leerstring enthält.

              IF ($_GET['showAK'] != "") {
              

              Das gibt immer so unschöne Notice-Meldungen, wenn der Key nicht in $_GET enthalten ist. Besser ist es, empty() zu verwenden. Das ist quasi ein umgkehrtes isset(), und prüft zudem noch den Wert, ob er falsy ist.

              dedlfix.

              1. Hallo dedlfix,

                yup, hast recht. Es wird auch Seitenabrufe ohne die Parameter geben.

                Rolf

                --
                sumpsi - posui - obstruxi
              2. Hallo Dedlfix,

                Allerdings hast Du dann auch die SELECT-Boxen in der Eingabe, wo nichts ausgewählt ist, d.h. Du musst nicht mit isset abfragen, sondern darauf, ob der Parameter einen Leerstring enthält.

                IF ($_GET['showAK'] != "") {
                

                Das gibt immer so unschöne Notice-Meldungen, wenn der Key nicht in $_GET enthalten ist. Besser ist es, empty() zu verwenden. Das ist quasi ein umgkehrtes isset(), und prüft zudem noch den Wert, ob er falsy ist.

                Das kann aber ins Auge gehen, wenn man ohne weitere Maßnahmen nach dem Wert "0" oder "" sucht.

                isset($_GET[suchspalte]) ist also definitiv die bessere Wahl für die Parameterübergabe und anschließend muss noch eine Plausibilitätskontrolle bzw. Escaping des Wertes gegen die Datenbank stattfinden. Es wäre sinnlos (oder deutet auf einen Angriff hin), in einer numerischen Spalte nach "Übel" zu suchen, usw.

                LG + Gesundheit
                Localhost

  4. Hallo,

    ich finde es ziemlich gut, wenn man sich selbst eine Lösung ausdenkt und rumprobiert. Der Lerneffekt ist dabei sehr hoch. Zumindest bei mir war und ist dies der Fall.

    Ich finde nur, dass man da schnell sehr viel zu tun hat, wenn sich die Tabellen ändern, also neue Spalten hinzukommen oder wegfallen oder es um weitere Tabellen geht. Ich ziele da etwas auf die Wiederverwendbarkeit des Codes ab.

    Jemand schlug Javascript für die Sortierung vor. Ich halte das auch für sinnvoll (obwohl ich Javascript überhaupt nicht mag), da dies wesentlich flexibler ist. Es gibt da bereits ein schönes jQuery-basiertes Plugin (tablesorter 2.0). Es lässt sich einfach in jede Tabelle integrieren, indem man der Tabelle eine css-Klasse zuweist. Und man erhält einen Filter sowie multiple Spaltensortierung. Ich nutze es gern für meine Admin-Seiten.

    Das tolle ist auch, dass man sich workload spart, was gerade bei größeren Projekten zu Geschwindigkeitseinbußen führen könnte, da die Datensätze nicht jedesmal neu abgerufen werden.

    Weitere Infos und ein Beispiel findest du auch hier:

    https://mottie.github.io/tablesorter/docs/#Getting-Started

    Beste Grüße und alles Gute

    Vapita

    1. Hallo vapita,

      Es gibt da bereits ein schönes jQuery-basiertes Plugin (tablesorter 2.0).

      Es gibt da bereits einen sehr schönen jQuery-freien Tabellensortierer aus dem Hause Berkemeier.

      indem man der Tabelle eine css-Klasse zuweist.

      Es gibt jedoch keine CSS-Klassen.

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
  5. Vielen Dank für all eure Ideen und Ansätze,

    dedlfix und Rolf treiben mich wieder an kognitive Grenzen. Das schau ich mir aber trotzdem weiter an.

    Im Gegensatz zur "ersten Version" spare ich jetzt zwar bereits unmengen an Codezeilen (das wollt ihr gar nicht sehen wie das ausgesehen hat ...), aber wenn man auch das aktuelle weiter runterbrechen könnte wäre das auch schön. Außerdem, lernt man ja nie aus :)

    Auch die Javascript Variante wäre eine gute Idee. So spart man sich die Last auf dem Server, und schieb es zum Client. Allerdings habe ich mit diversen anderen "Fertigscripten" auch bereits schlechte Erfahrungen gemacht, da sie nicht in jedem Browser sauber laufen und manchmal komisches Verhalten zeigen.

    Einen Sorter hatte ich bspw. schon einmal für eine andere Seite im Einsatz, das funktionierte aber immer nur 1x.

    Das kombinierte Sortieren und Filtern war ja jetzt das Problem.

    Wir fahren hier auch zu einem Teil noch mit dem IE 11, wo javascripte auch manchmal komische Sachen machen.

    Aber auch das (die 2 vorgeschlagenen) sehe ich mir nochmal an.

    Danke für eure Hilfe. Ihr seit die Besten :)

  6. Lieber PHP-Neuling,

    ich habe diesen Thread gelesen und mir fällt auf, dass Du drei Dinge miteinander zusammenwirfst:

    1. DB-Daten sortiert ausgeben (nach $kriterien)
    2. Sortierwünsche des Users in einer Session speichern und berücksichtigen
    3. clientseitige Sortierung mittels JavaScript im Browser

    Vielleicht sehe ich das falsch, aber der dritte Punkt macht die anderen beiden völlig überflüssig. Lassen wir ihn lieber einmal beiseite.

    Kümmern wir uns rein um diese Frage: "Was will der User als Sortierkriterien?"

    Dazu braucht es sowohl eine Liste an möglichen Sortierkriterien (in aller Regel die Spalten Deiner DB-Daten) und eine Richtung (auf- oder absteigend), die mit passenden Eingabefeldern für den User wählbar sein soll.

    Frei erfundenes Beispiel mit allen (hier nur drei) möglichen Kategorien:

    1. Kundennummer (aufsteigend, kleinste zuerst)
    2. Datum (absteigend, neueste zuerst)
    3. Preis (aufsteigend)

    Wir haben also zuerst das Problem, dass wir die Reihenfolge der möglichen Kategorien auswählbar machen müssen. Danach kommt noch dazu, dass man für jede Kategorie entscheiden können soll, in welcher Richtung diese sortiert wird.

    Ein direkter Lösungsweg ist das Anbieten dieser Kategorien als Dropdown-Menüs:

    <ol>
      <li>
        <label>
          Kriterium
          <select name="sort_by[1][cat]">
            <option value="">-- nichts --</option>
            <option value="date">Datum</option>
            <option value="customer_id">Kundennummer</option>
            <option value="price">Preis</option>
          </select>
        </label>:
        <label>
          aufsteigend
          <input type="radio" selected="selected" name="sort_by[1][dir]" value="asc">
        </label>
        /
        <label>
          aufsteigend
          <input type="radio" name="sort_by[1][dir]" value="asc">
        </label>
      </li>
    ...
    </ol>
    

    Wir sehen eine sortierte Liste mit in Beschriftungen eingebetteten Eingabefeldern. Das erste ist eine Auswahlbox, die als erste Option einen leeren Wert hat. Für PHP kann man als Feldnamen etwas mit eckigen Klammern verwenden, damit das auf Serverseite später ein Array wird. Lässt sich dann besser in einer Schleife abarbeiten. Es geht prinzipiell aber auch anders.

    Die Liste sollte noch zwei weitere <li> mit (bis auf die name-Werte) identischen Inhalten haben, damit wir drei mögliche Kriterien angeben können.

    Unschön: Man kann dreimal das gleiche Kriterium mit unterschiedlichen Richtungen angeben. Das ist nicht gut. Eine Lösung wäre mit verketteten Auswahllisten zu arbeiten, deren Verkettung eben dafür sorgt, dass bereits ausgewählte Werte in den Dropdown-Boxen in allen folgenden nicht mehr anwählbar sind. Das erfordert JavaScript.

    Auf der Serverseite kommt dann in unserem gewählten Beispiel das hier an:

    $_POST = array(
      'sort_by' => array(
        1 => array(
          'cat' => 'customer_id',
          'dir' => 'asc'
        ),
        2 => array(
          'cat' => 'date',
          'dir' => 'desc'
        ),
        3 => array(
          'cat' => 'price',
          'dir' => 'asc'
        )
      )
    );
    

    Dieses Array (also der gesamte Inhalt von $_POST['sort_by']) kann dann nach erfolgreicher Filterung (Plausibilitätsprüfung) in Deine Session übernommen werden. Danach kannst Du dann die Sortierung für Deine SQL-Statements entsprechend bauen.

    Die Plausibilitätsprüfung ignoriert alle Array-Einträge, die einen ungültigen Wert für 'cat' aufweisen und verwendet asc als Standardwert für 'dir', falls da nichts oder nichts Erlaubtes darin steht. Damit kann dann das Formular auf der nächsten Seite mit den in der Session gespeicherten Werten vorbelegt werden. Das JavaScript verkettet die Auswahllisten wieder und sorgt dafür, dass die Verfügbarkeit der Kategorien in den Boxen entsprechend begrenzt wird.

    Liebe Grüße

    Felix Riesterer

    1. ich habe diesen Thread gelesen und mir fällt auf, dass Du drei Dinge miteinander zusammenwirfst:

      1. DB-Daten sortiert ausgeben (nach $kriterien)
      2. Sortierwünsche des Users in einer Session speichern und berücksichtigen
      3. clientseitige Sortierung mittels JavaScript im Browser

      Vielleicht sehe ich das falsch, aber der dritte Punkt macht die anderen beiden völlig überflüssig. Lassen wir ihn lieber einmal beiseite.

      Klar erscheint das als „hyperliquid“ - aber es könnte durchaus sinnvoll sein.

      Nämlich dann wenn man dem Benutzer die Möglichkeit bieten will bei einer Rückkehr zur Seite sofort gemäß den letzten Wünschen sortierte Daten vorzufinden statt die Tabelle erst in JS zu sortieren oder aufzubauen.

      Stellt sich die Frage ob das sinnhaft ist. Entweder ist die Datenbank „hoch volatil“ - dann sollte ggf. auf jedes Cachen verzichtet werden und die JS-Sortierung macht keinen Sinn oder aber die Daten sind langzeitstabil - dann stellt sich die Frage ob man nach Empfang der Daten überhaupt noch mit dem Server "diskutiert".

      Ein weiterer Aspekt wäre die Paginierung. Aber die ist bei volatilen (und sortierten) Daten sowieso eine Geschichte bei der die Diskussion kaum befriedigendes Ende finden kann.

      BTW:

      Abfrage des Zeitpunkts der letzten Änderung einer Tabelle:

      SELECT UPDATE_TIME
      FROM   information_schema.tables
      WHERE
          TABLE_SCHEMA = '$schema' AND
          TABLE_NAME   = '$table';
      

      Letzte Änderung aller Tabellen eines Schemas (z.B. weil die Daten aus Joins stammen):

      SELECT
         MAX(`UPDATE_TIME`) AS 'DB_UPDATE_TIME'
      FROM `information_schema.tables`
      WHERE `TABLE_SCHEMA` = '$schema'
      

      Damit kann man dann einen ETAG oder ein anderes Cache-Konstrukt bauen bzw. beim Paginieren sortierter Daten warnen.

  7. Ich habe, weil ich gerade ein wenig Zeit hatte und die Möglichkeit für eine Finger- und Hirnübung sah, das von mir verstandene kurzerhand und sicher schlampig in ein Skript für die Konsole verpackt ($_GET und $_SESSION werden simuliert).

    Je nach Plan ist es womöglich fast perfekt aber wahrscheinlich nicht... Vielleicht liefert Dir das ja Ansätze.

    <?php
    
    ## Session für CLI simulieren:
    #/*
    if (is_readable('session.json') ) {
        $_SESSION = json_decode( 
           file_get_contents( 'session.json' ),
           JSON_OBJECT_AS_ARRAY
        );
    } else {
      	$_SESSION = [];
      	file_put_contents(
    		'session.json',
    		json_encode( [] )
    	);
    }
    #*/
    
    ## $_GET für CLI simulieren:
    #/*
    $_GET['showFoo']=1; 
    $_GET['showBar']=0;
    $_GET['showBaz']=0;
    $_GET['showTok']=1;
    
    $_GET['sortFoo']=1; 
    $_GET['sortBar']=0;
    $_GET['sortBaz']=0;
    $_GET['sortTok']=-1;
    
    $_GET['sortOrder']='Foo,Tok';
    #*/
    
    ## Simulation: 
    ## In der Realität die Spalten aus der Datenbank holen: 
    ## "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '$schema' AND TABLE_NAME = '$table';"
     
    $arColumns = ['Foo', 'Bar', 'Baz', 'Tok'];
    
    
    ## Programm ##################
    
    
    if ( isset( $_SESSION['ShowColumns'] ) ) {
        $arShowColumns = array_keys( $_SESSION['ShowColumns'] );
    } else {
        $arShowColumns = [];
    }
    
    $allowed = [1,0,-1];
    foreach ( $arColumns as $column ) {
    	if ( isset( $_GET['show'.$column ] ) ) {
    		if ( ! in_array( $_GET['show'.$column], $allowed ) ) {
    			trigger_error(
    			    'Wert '.$_GET['show'.$column].' in $_GET["show'.$column.'] ist nicht erlaubt.',
    			    E_USER_ERROR
    			);
    		} 
    		if ( 1 == $_GET['show'.$column ] ) {
                 $_SESSION['ShowColumns'][$column] = true;
    		} elseif ( 0 == $_GET['show'.$column ] ) {
    		     unset( $_SESSION['ShowColumns'][$column] );
    		}
    	}
    	if ( isset( $_GET['sort'.$column ] ) ) {
    		if ( ! in_array( $_GET['sort'.$column], $allowed ) ) {
    			trigger_error(
    			    'Wert '.$_GET['sort'.$column].' in $_GET["show'.$column.'] ist nicht erlaubt.',
    			    E_USER_ERROR
    			);
    		} 
    		if ( 1 == $_GET['sort'.$column ] ) {
                 $_SESSION['SortColumns'][$column] = 'ASC';
    		} elseif ( -1 == $_GET['sort'.$column ] ) {
    			$_SESSION['SortColumns'][$column] = 'DESC';
    		} else {
    		     unset( $_SESSION['SortColumns'][$column] );
    		}
    	}	
    }
    
    if ( isset($_GET['sortOrder'] ) ) {
    	$_SESSION['SortOrder']=[];
    	$sortOrder = explode( ',', $_GET['sortOrder'] );
    	foreach ($sortOrder as $item ) {
    		if (in_array( $item, $arColumns ) ) {
    			$_SESSION['SortOrder'][] = $item;
    		} else {
    			trigger_error(
    			    'Wert '.$_GET['sort'.$column].' in $_GET["sortOrder."] ist nicht erlaubt.',
    			    E_USER_ERROR
    			);			
    		}
    	}
    } 
    
    if ( ! isset( $_SESSION['SortOrder'] ) ) {
    	trigger_error(
    		'Wenn sortiert werden soll muss die sortOrder angegeeben werden',
    		E_USER_ERROR
    	);		
    }
    
    file_put_contents(
    	'session.json',
    	json_encode( $_SESSION, JSON_PRETTY_PRINT )
    );
    
    echo file_get_contents('session.json');
    
    # Welche Spalten sollen gezeigt werden?
    
    $selects = [];
    foreach ( array_keys( $_SESSION['ShowColumns'] ) as $key ) {
    	if ( $_SESSION['ShowColumns'][$key]) {
    		$selects[] = '`' . $key . '`';
    	}
    }
    
    # wie soll sortiert werden?
    
    $sortOrders = array();
    
    foreach(  $_SESSION['SortOrder'] as $item ) {
    	if ( $_SESSION['SortColumns'][$item] == 'DESC' ) {
    	   $sortOrders[] = '`' . $item . '` DESC' ; 	
    	} else {
    	   $sortOrders[] = '`' . $item . '`' ; 	
    	}
    }
    
    if ( count( $sortOrders ) ) {
    	$orders = ' ORDER BY ' . implode( ', ', $sortOrders );
    } else {
    	$orders = '';
    }
    
    $sql = 'SELECT ' . implode( ', ' , $selects ) . ' from `Tabelle`' . $orders;
    
    echo PHP_EOL, $sql, PHP_EOL;
    
    1. boah ... ist das kompliziert :D

      Eure ganzen tollen Ideen zur durchwursten wird mich wahrscheinlich einige Tage beschäftigen :D

      Da aber dem ein oder anderen nicht ganz klar ist, was ich eigentlich vor habe, versuche ich es nochmal zu erklären. Nebenbei erwähnt sei, dass mein Quelltextsparender Code der SESSION arrays wohlgesonnen funktioniert.

      Meine Seite lädt eine Tabelle aus einer Datenbank. Verbunden durch IDs werden die columns in den Spalten angezeigt. Damit die Größe veraunschaulicht werden kann: Aktuell herrschen 400 DB Einträge vor. Also nichts von wegen BIG DATA

      Standardeinstellung der Seite ist ein Limit des Selects von 50 Einträgen. Man kann das ändern. Das wird dann auch in einer SESSION gespeichert, damit beim Rückkehren die Einstellung erhalten bleibt.

      Nun habe ich (per select) über der jeweiligen Tabellenspalten Pfeile verbaut, welche das sortieren in ASC oder DESC erlauben (über GET und neuem SELECT). Das GET sieht dann bspw. so aus (https://SeitederSeiten.de/index.php?sort=KERN_SPALTE1 DESC).

      Diese GET-Pfeile habe ich für jede Spalte erstellt, sodass nach jeder Spalte Auf- oder Abwärts sortiert werden kann.

      Gleichzeitig befinden sich im TH SELECT-Boxen, welche per DISCTINCT (keine dopplungen) alle möglichen Spalteneinträge aufzeigen. Wählt man nun einen Eintrag aus einer der Boxen, wird die Seite mit angepasstem SELECT neu geladen.

      Bspw. Standortübersicht: Berlin, Hamburg, Rostock, München. Zunächst werden alle Einträge mit allen Standorten angezeigt. Nach SELECT-Auswahl von Berlin wird die Seite mit neuem SELECT Befehl neu geladen (SELECT * from DB WHERE Standort = '$VARIABLEAUSGET' -> was in diesem Falle 'Berlin' beinhalten würde <- ;)

      Auch diese Boxen habe ich (fast) über jeder Tabellenspalte.

      Das war jetzt schon wieder viel zu viel geplappere ... Aber ich hoffe ihr könnt euch halbwegs vorstellen, wie der IST Zustand ist.

      Meine Spalten heissen bspw.

      Standort, Durchführungsort, Datum, Status, Art des Vorgangs etc. pp.

      Ich kann nun nach jedem Kriterium einzeln sortieren. Ich möchte das aber noch kombinieren. Also:

      Zeige mir ALLE Einträge von Standort Berlin (Dropdown, Berlin gewählt), und zusätzlich noch alle Einträge vom 17.02.2021 (Dropdown Datum, 17.02.2021).

      Nun zeigt mir mein INDEX nur die Einträge aus Berlin (zuerst gewählt), die am 17.02.2021 erstellt worden sind.

      Und als wäre das nicht schlimm genug ... Wenn nun nach dieser Art sortiert/gefiltert worden ist, soll sich die Seite diesen Quark auch noch merken. Wenn ich nun also über den sortierten INDEX in eine Detailseite (EDIT) gehe, und dann ZURÜCK zum INDEX gehe, soll die Sortierung aller gewählten Kriterien stehen bleiben.

      Wenn ich will, möchte ich auch nach Standort, Datum, Status und Art des Vorgangs sortieren.

      Deswegen brauche ich die SESSION Variablen.

      Ich hoffe das war jetzt etwas verständlicher. Ich verstehs ja manchmal selbst nicht :D

      Vielen lieben Dank euch allen

      1. Hallo,

        offen ist imho immer noch die Frage, ob "Echtzeitreaktion" ("Dynaset"), oder (persistente) Abfragezeitpunktrelevanz ("Snapshot") notwendig/erwünscht ist. Oder soll eine Kombination aus beiden gebaut werden? Das wären dann die höchsten Weihen.

        Und bei "Echtzeitreaktion" gibt es immer noch die Unterscheidung zwischen Pull- und Pushbezug. D.h., dass Änderungen am Datenbestand erst bei der nächsten Benutzerhandlung oder eventuell sofort zum Client durchschlagen (->Websockets).

        Bevor Du die Bedienmöglichkeiten planst, solltest Du daher die Art der Datenkoppelung festlegen.

        LG + Gesundheit
        Localhorst

      2. Deswegen brauche ich die SESSION Variablen.

        Nein. Ich sehe eher Bedarf an einem Plan.

        Die erste Frage ist nämlich, warum Du das mit einer Session verkomplizieren willst. Es gibt nämlich auch Cookies, die man mittels JS im Browser setzen kann. Das dürfte die Sache "etwas vereinfachen".

        Die Session-ID wird übrigens auch in einem Cookie gespeichert.

        1. Hallo,

          Deswegen brauche ich die SESSION Variablen.

          Nein. Ich sehe eher Bedarf an einem Plan.

          Die erste Frage ist nämlich, warum Du das mit einer Session verkomplizieren willst. Es gibt nämlich auch Cookies, die man mittels JS im Browser setzen kann. Das dürfte die Sache "etwas vereinfachen".

          Die Session-ID wird übrigens auch in einem Cookie gespeichert.

          Wenn zuvor die Frage der gewünschten Datenkoppelung geklärt wurde, könnten hier eventuell auch URL-Parameter für die gewünschten Spalten und deren Sortierung die richtige Wahl sein.

          Kommt darauf an, ob man die Art der Sicht mit der URL konservieren/weitergeben können soll, oder nicht. Der Inhalt der Sicht sollte hingegen immer von den Rechten des Requesters auf den Datenbestand abhängen. Dazu könnten dann Cookies dienen.

          Und sowie Rechte im Spiel sind, sollte HTTPS Pflicht sein!
          Das Rechtemodul / die Rechteschicht sollte ungebrochenes TLS also immer als erstes abprüfen.

          LG + Gesundheit
          Localhorst

        2. Hey Raketentyp

          du meinst, "verkomplizieren". Wie ihr sicher immer wieder feststellt bin ich noch Anfänger in Sachen Entwicklung. Das gilt nicht nur für PHP, sondern ganz generell.

          Die Annahme, dass immer was erweitert wird, beschreibt auch ganz genau was hier bei mir passiert. Mir persönlich gefällt das aber ganz gut, weil dadurch der Lerneffekt enorm ist.

          Der Sortiererei wegen musste ich etliches komplett neu schreiben. Das war nervig, räumte aber übelst auf und schafft ein neues Verständnis.

          Nun .. Cookies .. Ja, kann man sicher auch setzen. Aber ist denn das wirklich einfacher als mein aktueller Weg?

          Alles was ich tue ist, mir den gewählten Wert aus dem Dropdownfeld in eine Session zu schreiben.

          Damit ich diesen dann für den dynamischen SELECT auseinandernehmen kann, schreibe ich alles in die selbe Session mit dimension.

          Ich habe für die Sortiererei vorher ca frünftausendzig Zeilen Quellcode gehabt. Nun habe ich noch 8.

          Es gibt so viele Wege (die meisten hier verstehe ich noch gar nicht) ein Ziel zu erreichen.

          Aber ab und zu frage ich mich mittlerweile: Ist denn das vorgeschlagene wirklich "einfacher", effektiver und besser nachzuvollziehen?

          Was spricht gegen die SESSION? Kann da was kaputt gehen ?

          Warum lieber Javascript Tabellenfuddelei als sauber neu laden? (Limit ist eh auf 50) Ich versuche eher mich möglichst von Javascript fernzuhalten

          Warum cachen anstatt neu zu laden? Da können ja dann schon wieder Einträge eines anderen Nutzers fehlen?

          Ich frage diese Fragen tatsächlich, weil ich verstehen will warum das eine besser ist als das andere, und mein Weg am Ende (wenn die DB wächst) wirklich Ärger macht. Einen "besten Weg" gibt es nicht in der Entwicklung, so viel habe ich schon verstanden. Aber nachhaltig und effizient gibts

          Danke euch :)

          Grüße

          1. Lieber PHP-Neuling,

            Was spricht gegen die SESSION? Kann da was kaputt gehen ?

            mir gefällt die Idee mit der Session ganz gut. Sie bietet sich immer dann an, wenn man ohnehin schon eine Session hat, weil man z.B. einen Login damit umsetzt.

            [Edit]Wenn Du keinen Login-Mechanismus hast, dann kannst Du die Sortierwünsche des Users nicht serverseitig speichern. Da ist ein Cookie tatsächlich sinnvoll, weil es beim User im Browser verbleibt.[/Edit]

            Warum lieber Javascript Tabellenfuddelei als sauber neu laden? (Limit ist eh auf 50) Ich versuche eher mich möglichst von Javascript fernzuhalten

            Das ist Geschmackssache. Wenn man im Intranet sitzt, ist das von der Performance her Jacke wie Hose. Allerdings ist die Bedienbarkeit mit JavaScript geschmeidiger lösbar. Du hast ja jetzt schon das Problem, dass Du in den Tabellenüberschriften nicht einstellen kannst, nach welcher der Kategorien zuerst sortiert werden soll.

            Warum cachen anstatt neu zu laden? Da können ja dann schon wieder Einträge eines anderen Nutzers fehlen?

            Das meinte Localhorst mit "volatil". Du beantwortest hier im Wesentlichen seine Frage mit "ja, muss immer wieder frisch geladen werden".

            Liebe Grüße

            Felix Riesterer

            1. Hi Felix,

              da ich einen Loginautomatismus nutze, und auch andere Sachen bereits in SESSIONs speichere (Berechtigungsfragen etc) ist session_start eh aktiv.

              Das Kategoriensortieren kann ich allerdings nicht bestätigen. Durch die Dropdowns kann nach jeder Kategorie nachsortiert werden. Standardsortierung liegt auf "letzte Änderung".

              Auch das Nutzer mit entsprechender Berechtigung nur eigene Standorte sehen/bearbeiten dürfen lässt sich so alles regeln. Sogar sehr gut.

              Ich gebe aber zu, dass ich etwas im Wald stehe, wenn ich bspw. 1 Jahr ausfalle und mir den Quelltext entsprechend nicht mehr ansehen kann. Hierfür kommentiere ich aber was das Zeug hält.

              Ob aber ein anderer mit meinem Code was anfangen kann, weiß ich nicht. Könnte schwierig werden. Aber das ist glaube ich auch relativ normal, oder? Und würde sich sicherlich auch mit javascripten nicht großartig ändern.

              Ich hoffe nur, dass sich das stete Neuladen nicht später auf die Perfomance auswirkt, wenn statt 400 eventuell 5000 Einträge vorhanden sind. Hier setze ich auf den "limit" faktor, der die auszulesenden Datensätze grundlegend beschränkt.

              Man darf es ja gar nicht erwähnen ... Aber neben der Startseitensortiererei (INDEX) gibt es ja auch noch eine echte Datenbanksuche, bei der noch viel feiner gefiltert werden kann.

              Wozu ich mir den Aufwand jetzt gemacht habe weiß ich tatsächlich manchmal selbst nicht.

              Aber .. es macht halt auch immer Spaß und treibt mir pippi in den Schlüppi, wenn so ein Quark dann am Ende sogar funktioniert 😁

              Hab ich schon erwähnt, dass ich euch alle toll finde? 🤘 👍 😀 💙

              1. Lieber PHP-Neuling,

                da ich einen Loginautomatismus nutze, und auch andere Sachen bereits in SESSIONs speichere (Berechtigungsfragen etc) ist session_start eh aktiv.

                dann kannst Du ja die Sortierpräferenzen sogar in Deiner Applikation speichern. Dann hat es der User auf egal welchem Gerät immer "wie beim letzten Mal".

                Das Kategoriensortieren kann ich allerdings nicht bestätigen. Durch die Dropdowns kann nach jeder Kategorie nachsortiert werden. Standardsortierung liegt auf "letzte Änderung".

                Kannst Du denn nach mehr als nur einer Kategorie sortieren lassen? Deine Beschreibung mit den Dropdowns in den Tabellenüberschriften legt das nahe. Aber kann man auch sagen, welche der Kategorien zuerst gilt, und welche danach?

                Auch das Nutzer mit entsprechender Berechtigung nur eigene Standorte sehen/bearbeiten dürfen lässt sich so alles regeln. Sogar sehr gut.

                Klar, das ergibt sich aus Berechtigungen-Konzept.

                Ich gebe aber zu, dass ich etwas im Wald stehe, wenn ich bspw. 1 Jahr ausfalle und mir den Quelltext entsprechend nicht mehr ansehen kann. Hierfür kommentiere ich aber was das Zeug hält.

                Das ist sicherlich das Beste an Deinem Code. Auch ich habe mir schon vor Jahren angewöhnt aus allen Rohren zu feuern, wenn es um das Kommentieren meines Codes geht. Das hilft!

                Ob aber ein anderer mit meinem Code was anfangen kann, weiß ich nicht. Könnte schwierig werden. Aber das ist glaube ich auch relativ normal, oder? Und würde sich sicherlich auch mit javascripten nicht großartig ändern.

                Das kommt sehr darauf an, wie Du kommentierst.

                Ich hoffe nur, dass sich das stete Neuladen nicht später auf die Perfomance auswirkt, wenn statt 400 eventuell 5000 Einträge vorhanden sind.

                DBMS sind darauf spezialisiert, dass da keine Unterschiede in der Performance entstehen. Und solange Du von < 10000 Einträgen sprichst... Interessant werden solche Abfragen erst, wenn Du komplexere JOINs und Subselects verwendest. Da können ungünstige Datenmodelle oder Abfrageformulierungen erhebliche Performance-Einbrüche verursachen.

                Man darf es ja gar nicht erwähnen ... Aber neben der Startseitensortiererei (INDEX) gibt es ja auch noch eine echte Datenbanksuche, bei der noch viel feiner gefiltert werden kann.

                Kennst Du phpMyAdmin? Damit kannst Du alles an Suchen realisieren, was Du willst. Die haben auch einen Tabellensortierer und eine Paginierung.

                Wozu ich mir den Aufwand jetzt gemacht habe weiß ich tatsächlich manchmal selbst nicht.

                Hobby anyone? Und wenn man etwas geschaffen hat, das anderen die Arbeit erleichtert, dann ist das durchaus mit Glücksgefühlen verbunden.

                Hab ich schon erwähnt, dass ich euch alle toll finde? 🤘 👍 😀 💙

                Vielen Dank! :D

                Liebe Grüße

                Felix Riesterer

                1. Kannst Du denn nach mehr als nur einer Kategorie sortieren lassen? Deine Beschreibung mit den Dropdowns in den Tabellenüberschriften legt das nahe. Aber kann man auch sagen, welche der Kategorien zuerst gilt, und welche danach?

                  Nein, dass kann ich tatsächlich nicht. "Der oberste Wert gilt" könnte man sagen

                  Überlicherweise ist dies die Standortangabe. Da aber nochmal drunter zu sortieren halte ich tatsächlich nicht für notwendig.

                  Zum Thema performance ... Also nicht, dass es eh klar ist ... Aber der Unterschied vom gammeligen IE11 zu Google Chrome ist erstaunlich

                  Im IE pennt das CSS förmlich. Animationen, selbst reines coloriertes hovern, haken richtig im IE.

                  Chrome hingegen macht das wie Gulasch. Ratzfatz Paprika dran und fertig 😁

                  Ich hoffe das ich den uralten Käse hier irgendwann verbannt bekomme 😔

          2. Hallo PHP-Neuling,

            ich habe es so verstanden, dass du gern folgendes haben möchtest:

            • Sortieren der Tabellen über mehrere Spalten
            • Speichern der Sortierung beim Neuladen der Seite oder nach der Wiederkehr
            • Spaltenfilter (Suchfunktion?)
            • Keine aufwendige Implementierung
            • Schnelles Anwenden auf jede beliebige Tabelle
            • optional Paging möglich

            Ich habe herumprobiert und etwas gefunden, das dem gerecht wird und nach meinem Test auch unter IE11 funktioniert. Ja, es ist Javascript, bzw. JQuery, aber es tut genau das, was es soll.

            Hier findest du ein Beispiel, dass ich extra auf meiner Seite zum Testen implementierte:

            https://www.ringhorn.de/base/index

            Durch Klicken mit [Umschalt]-Taste kann man nach mehreren Spalten sortieren. Wenn du einen neuen Eintrag hinzufügst, die Seite aktualisierst oder sonstiges tust, bleibt die Sortierung erhalten.

            Implementierung

            HTML

            <!-- choose a theme file -->
            <link rel="stylesheet" href="/path/to/theme.default.css">
            <!-- load jQuery and tablesorter scripts -->
            <script type="text/javascript" src="/path/to/jquery-latest.js"></script>
            <script type="text/javascript" src="/path/to/jquery.tablesorter.js"></script>
            
            <!-- tablesorter widgets (optional) -->
            <script type="text/javascript" src="/path/to/jquery.tablesorter.widgets.js"></script>
            
            <script type="text/javascript">
            $(document).ready(function() {
                $("table").tablesorter({
                    theme : "dark",
                    widthFixed: true,
                    widgets : [ "filter", "columns", "zebra", "saveSort" ],
                    widgetOptions : {
                        // class names added to columns when sorted
                        columns: [ "primary", "secondary", "tertiary" ],
                        // reset filters button
                        filter_reset : ".reset",
                        // extra css class name (string or array) added to the filter element (input or select)
                        filter_cssFilter:
                            ''
                    }
                })    
            });
            </script>
            

            Füge anschließend deiner Tablle .tablesorter hinzu:

            <table class="tablesorter">
            ...
            
            

            Vielleicht ist es etwas für dich, und wenn doch nicht, auch nicht tragisch. Ansonsten ist die Implentierung recht übersichtlich und man muss sich nicht weiter drum kümmern bei der Ausgabe der Tabellen.

            Weitere Infos findest du auch hier:

            https://mottie.github.io/tablesorter/docs/

            Beste Grüße und alles Gute

            Vapita

            1. danke vapita. schau ich mir auch mal an :)

      3. Tach!

        Ich hoffe das war jetzt etwas verständlicher. Ich verstehs ja manchmal selbst nicht :D

        Alles schön und gut. Das sind Feature-Wünsche, die nicht das erste Mal umgesetzt wurden. Man fängt klein an und zeigt die Daten in einer Tabelle. Dann kommen die Wünsche nach Paging, Filterung und Sortierung, und man flanscht das an. Der nächste Anwender kommt und hätte gern noch die Möglichkeit zu gruppieren, andere wollen den Filter erweitert haben, um komplexere Suchszenarien abdecken zu können. Am Ende hat man einen organisch gewachsenen Haufen Code, den mitunter das Zukunfts-Ich nur noch ungern anfasst. Wenn man viel Zeit hat, und das alles auch macht, um zu lernen, und der Weg zum Ziel gehört, dann nur zu. Ansonsten gibt es auch die eine oder andere Fertigkomponente, die mit überschaubarem Einarbeitungsaufwand das alles und vielleicht noch mehr (zum Beispiel Export, Inline-Editor) zu bieten hat. Solche Komponenten findet unter dem Suchbegriff Datagrid.

        dedlfix.

        1. Hallo dedlfix,

          Solche Komponenten findet unter dem Suchbegriff Datagrid.

          Ich hab mal das Grid von Telerik (Kendo UI) genutzt (nutzen müssen), das macht die Arbeit auf dem Server auch nicht leichter. Und es bringt einen unglaublichen Haufen Kram mit, den man erstmal in die eigene Seite einpassen muss.

          Ich glaube, die Auswahl einer Datagrid Komponente ist ein Projekt für sich...

          Rolf

          --
          sumpsi - posui - obstruxi