Margit Kraus: variable mit html ausgeben

Hallo Zusammen,

ich habe ein kleines Problem:

Ich möchte mit html ein Bild aufrufen (das ist noch nicht das Problem, das funktioniert.).

<img src="https://url/image/bild.jpg" alt="Ein Bild">

Allerdings sollte das "bild.jpg" variable sein (= die neueste Datei im image Verzeichnis).

Das funktioniert auch mit folgendem Code:

<?php
// Neueste Datei in einem Verzeichnis anzeigen

$path = 'mein-pfad/'; /***/***/***/***/default-website

$maxTsFile = 0;
$nFileName = "";
foreach(glob($path . '*.*') as $fileName) {
  $ts = filemtime($fileName);
  if($ts > $maxTsFile) {
    $maxTsFile = $ts;
    $nFileName = $fileName;
  }
}

echo "neuste Datei: " . $nFileName;
?> 

Jetzt kommt mein Problem:

Wie kommt die Variable $nFileName in den html code?

Also: <img src="https://url/image/$nFileName" alt="Ein Bild"> (was natürlich nicht funktioniert)?

Das Ganze findet in der index.php statt.

Ich bitte um eure Hilfe! Vielen Dank schon mal im Voraus für eure Mithilfe! (Hab wahrscheinlich ein Brett vor dem Kopf)

GLg Margit

  1. @@Margit Kraus

    Wie kommt die Variable $nFileName in den html code?

    Also: <img src="https://url/image/$nFileName" alt="Ein Bild"> (was natürlich nicht funktioniert)?

    Indem du ihn an dieser Stelle mit PHP reinschreibst:

    <img src="https://url/image/<?php echo $nFileName; ?>" alt="Ein Bild">
    

    Wobei unbedingt zu überlegen ist, ob in $nFileName Schadcode eingeschleust sein könnte. Wenn das nicht 100%ig verneint werden kann, ist das abzusichern:

    <img src="https://url/image/<?php echo htmlspecialchars($nFileName); ?>" alt="Ein Bild">
    

    Das ist aber nicht dein einziges Problem damit. Noch eins: Wie kommst der passende Alternativtext da rein?

    alt="Ein Bild" ist kein passender Alternativtext – für kein Bild.

    Handelt es sich um Bild, das für den Seiteninhalt wichtig ist? Oder ist das rein dekorativ? Im zweiten Fall wäre alt="" anzugeben.

    🖖 Живіть довго і процвітайте

    --
    When the power of love overcomes the love of power the world will know peace.
    — Jimi Hendrix
    1. Hallo Gunnar, ich danke dir ganz herzlich! Hat funktioniert. Und vor allem danke für die super schnelle Antwort! lg M

      1. ich danke dir ganz herzlich! Hat funktioniert. Und vor allem danke für die super schnelle Antwort!

        Je nachdem, wie viele Dateien in so einem Ordner liegen, kann man sich so allerdings ein Performanceproblem einhandeln. Alternative: einen Cronjob laufen lassen, der z.B. alle 5 Minuten diese Suche durchführt und den Dateinamen der neuesten Datei in ein TXT-File schreiben. In index.php dann den Dateinamen aus dem TXT-File auslesen.

        1. Hallo,

          ich danke dir ganz herzlich! Hat funktioniert. Und vor allem danke für die super schnelle Antwort!

          Je nachdem, wie viele Dateien in so einem Ordner liegen, kann man sich so allerdings ein Performanceproblem einhandeln.

          ja, das ist ein guter Einwand.

          Alternative: einen Cronjob laufen lassen, der z.B. alle 5 Minuten diese Suche durchführt und den Dateinamen der neuesten Datei in ein TXT-File schreiben. In index.php dann den Dateinamen aus dem TXT-File auslesen.

          Viele Shared-Hosting-Pakete bieten aber nicht den Luxus benutzerdefinierter cronjobs. Ich würde deshalb eher noch bei dem Script ansetzen, das regelmäßig neue Bilder anliefert. Soll doch dieses Script gleich mitloggen, wie das zuletzt gelieferte oder erzeugte Bild heißt - beispielsweise in der von dir vorgeschlagenen Textdatei.

          Einen schönen Tag noch
           Martin

          --
          Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
          1. Viele Shared-Hosting-Pakete bieten aber nicht den Luxus benutzerdefinierter cronjobs.

            Stimmt. Als Alternative gäbe es dann Webservices, mit denen man sowas einrichten kann.

            https://cron-job.org/en/faq/

            schaut ganz gut aus. Dann müsste man im PHP aber gucken, dass nur deren IPs den Aufruf starten können, um kein DOS-Fenster zu öffnen.

            Ich würde deshalb eher noch bei dem Script ansetzen, das regelmäßig neue Bilder anliefert. Soll doch dieses Script gleich mitloggen, wie das zuletzt gelieferte oder erzeugte Bild heißt - beispielsweise in der von dir vorgeschlagenen Textdatei.

            Soweit man ein Script hat, was für neue Bilder sorgt: ja. Bei Uploads z.B. via FileZilla ist schon wieder Essig…

            Weitere Idee: man baut in der index.php ein Intervall ein, was die Erzeugung des TXT-File nur alle 5 Minuten anwirft. Da muss man aber bzgl. TOCTOU dann aufpassen.

        2. Hallo Mitleser,

          je nach Hoster hat man keine Cronjobs, aber das Performanceproblem besteht durchaus. Es geht schnell, mit glob eine Dateiliste zu holen, aber der Zugriff auf die Dateiattribute ist zeitintensiv.

          Auf Shell-Ebene kann man - zumindest unter Windows, eine Auflistung von Dateien sortiert nach Zeit anfordern (dir /O:D-). DAS geht unter Windows fix, unter Linux weiß ich es nicht. Aber ich befürchte, dass die Ausführung von Shell-Befehlen je nach Hoster ebenfalls beschränkt ist.

          Man braucht also bei sehr vielen Dateien ggf. eine Alternative zum Cron-Job. Die erstgenannte Alternative kann auch dann brauchbar sein, wenn man Cron-Jobs machen kann.

          Möglichkeit 1
          Wie kommen die Bilder ins Verzeichnis? Geschieht das unter Kontrolle von PHP? In dem Fall kann nach jedem Schreiben eines Bildes die Infodatei, in der der Name der neuesten Datei steht, von PHP aktualisiert werden. Getreu dem Prinzip: Don't compute what you already know.
          Möglichkeit 1a
          Beim Einstellen von Bildern kann man einen Eintrag in einer Datenbank machen und das neueste Bild über einen SELECT ermitteln.
          Möglichkeit 2
          Zwei Image-Ordner. Einer mit den neuesten Bildern, einer mit dem Rest. Man könnte alle Bilder, die älter als 24h sind, in den "Archiv" Ordner verschieben. Macht man das aus dem PHP Script der Webseite, braucht man allerdings Synchronisiermechanismen, damit nicht zwei parallel laufende Requests die gleichen Dateien verschieben wollen. Nicht so ganz trivial.
          Möglichkeit 3
          Wenn man die neueste Datei ermittelt, schreibt man eine Dummy-Datei (mit einem wohldefinierten Namen), deren mtime den Zeitpunkt der letzten Ermittlung markiert und in der der Name der neuesten Datei steht. Bevor man die neue Ermittlung startet, prüft man das Alter dieser Datei. Ist sie älter als X Sekunden, ermittelt man neu. Auf diese Weise hat man die Verzögerung nur in gewissen Abständen.
          Möglichkeit 3a
          Kommen die Bilder "zufällig" irgendwoher - z.B. von einer Webcam - oder werden sie zu bestimmten Zeitpunkten gezielt vom Admin hochgeladen? Wenn es der Admin ist, kann man mit einem "Staging"-Ordner arbeiten, d.h. man lädt die neuen Bilder erstmal dorthin und lässt dann ein Script laufen, das die neueste Datei ermittelt, deren Namen in der Infodatei ablegt und danach die Bilder in den /image-Ordner verschiebt.
          Möglichkeit 4
          Folgen die Dateinamen der Bilder einem Schema? Würde eine auf- oder absteigende Sortierung der Namen dazu führen, dass die neueste Datei vorn in der Liste steht?

          So viele Möglichkeiten, so wenig Wissen über die Rahmenbedingungen...

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hallo,

            je nach Hoster hat man keine Cronjobs, aber das Performanceproblem besteht durchaus. Es geht schnell, mit glob eine Dateiliste zu holen, aber der Zugriff auf die Dateiattribute ist zeitintensiv.

            bei zunehmender Anzahl der Dateien wird auch das Sortieren zeitintensiv.

            Auf Shell-Ebene kann man - zumindest unter Windows, eine Auflistung von Dateien sortiert nach Zeit anfordern (dir /O:D-). DAS geht unter Windows fix, unter Linux weiß ich es nicht.

            Das geht unter Linux prinzipbedingt nicht ganz so fix, weil die Metadaten einer Datei (Timestamps, Größe, MIME-Typ, Besitzer, Zugriffsrechte uvm) nicht direkt im Verzeichniseintrag liegen, sondern in einem eigenen inode. Unter Windows ist das Erzeugen eines Verzeichnislistings mit allen Metadaten daher nur das Verfolgen einer linearen Clusterkette, während Linux für jeden Dateieintrag einen weiteren Lesezugriff auf einen anderen Cluster/inode braucht.

            Due nachfolgende Sortierung der Einträge ist dann vom Filesystem unabhängig.

            Aber ich befürchte, dass die Ausführung von Shell-Befehlen je nach Hoster ebenfalls beschränkt ist.

            Wohl wahr.

            So viele Möglichkeiten, so wenig Wissen über die Rahmenbedingungen...

            Einen schönen Tag noch
             Martin

            --
            Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
          2. Auf Shell-Ebene kann man - zumindest unter Windows, eine Auflistung von Dateien sortiert nach Zeit anfordern (dir /O:D-). DAS geht unter Windows fix, unter Linux weiß ich es nicht.

            ls -t
            

            Aber ich befürchte, dass die Ausführung von Shell-Befehlen je nach Hoster ebenfalls beschränkt ist.

            Man braucht also bei sehr vielen Dateien ggf. eine Alternative zum Cron-Job.

            Auf die Schnelle: Wenn eine neue Datei abgelegt wird ändert sich die Filemtime des Verzeichnisses. Die könnte man (in einem ANDEREN Verzeichnis) zusammen mit den Name des jüngsten Files serialisiert als Cache ablegen und dann beim Zugriff prüfen, ggf. die Datei erneuern:

            <?php
            
            function getNewestFile ( $dir, $cacheFile=false ) {
                if ( false == $cacheFile ) { 
            		$cacheFile =   '/tmp/newestFileCache_'
                             . str_replace( '/', '_', $dir )
                             . '.txt';
            	}
            	if ( is_readable ( $cacheFile ) ) {
            		$arr_cached = unserialize(
                        file_get_contents( $cacheFile )
                    );
            	} else {
            		$arr_cached = false;
            	}
                $dirmtime = filemtime( $dir ); 
                if ( 
            			( !	$arr_cached )
            		or  $arr_cached[0] < $dirmtime
            	) {
            		$maxTsFile = 0;
            		$nFileName = "";
            		foreach( glob( $dir . '/*.*' ) as $fileName ) {
            			$ts = filemtime( $fileName );
            			if( $ts > $maxTsFile ) {
            				$maxTsFile = $ts;
            				$nFileName = $fileName;
            			}
            		}
            		file_put_contents(
                    $cacheFile,
                    serialize( [ $dirmtime, $nFileName] )
                );
            		return $nFileName;
            	} else {
            		return ( $arr_cached[1] . '( From Cache )' );
            	}
            }
            
            # Test:
            echo getNewestFile( '/home/user/Dokumente' ) . PHP_EOL;
            

            Die mit Abstand beste Alternative ist es natürlich, durch ein Upload-Skript die neueste Datei irgendwo (Datei, Datenbank ) zu registrieren.

            Ach ja: Das . '( From Cache )' in der drittletzten Zeile der Funktion dient nur dazu, zu zeigen, dass das geht… Und es fehlt die Fehlerbehandlung - deshalb hab ich (das sonst scheinbar funktionierende) Skript als „schlecht“ markiert.

            Das Skript bemerkt (hier, auf ext4-Dateisystem) allerdings nicht, wenn existierenden Dateien verändert werden. Die modification time für Verzeichnisse ändert sich nur beim Löschen, Hinzufügen oder Umbenennen von Dateien in diesen.

            1. 		foreach( glob( $dir . '/*.*', GLOB_NOSORT ) as $fileName ) {
              

              Ohne den flag GLOB_NOSORT wird die Ausgabe von glob nach Namen sortiert. Das ist hyperliquid wenn man nach der neuesten Datei sucht und kostet ggf. einige Zeit.

              Dann ist da noch was:

              Die Modification-Time (auch die Create-Time) einer Datei kann - je nach Übertragungsprotokoll und bei der Übertragung auf den Server verwendete Optionen - die originale vom Herkunftsrechner sein. Dann kann es also sein, dass die zu letzt übertragene Datei nicht die neueste im Sinn des Programmes ist.

    2. Hallo Gunnar,

      für ein Minus reichts nicht, aber trotzdem:

      <img src="https://url/image/<?php echo htmlspecialchars($nFileName); ?>" alt="Ein Bild">
      

      Sowas sollte man nicht empfehlen. Dafür sind die Kurz-Tags <?= ?> da

      Besser:

      <img src="https://url/image/<?= htmlspecialchars($nFileName) ?>" alt="<?= $altText ?>">
      

      Es ist - gerade bei Serverumzügen - auch deutlich sinnvoller, Bilder nicht absolut zu referenzieren, sondern relativ.

      <img src="/image/<?= htmlspecialchars($nFileName) ?>" alt="<?= $altText ?>">
      

      Ob das im Einzelfall so leicht klappt, hängt natürlich von der Struktur der Website ab.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. @@Rolf B

        <img src="https://url/image/<?php echo htmlspecialchars($nFileName); ?>" alt="Ein Bild">
        

        Sowas sollte man nicht empfehlen. Dafür sind die Kurz-Tags <?= ?> da

        Es gibt sicher gute Gründe, die Kurzschreibweise zu verwenden. Und es gibt gute Gründe, das nicht zu tun. Mag jeder (jedes Team) für sich entscheiden. Von „Sowas sollte man nicht empfehlen“ würde ich nicht sprechen.

        Es ist - gerade bei Serverumzügen - auch deutlich sinnvoller, Bilder nicht absolut zu referenzieren

        Warum? Bei einem Serverumzug (d.h. Hosterwechsel) wird man wohl die Domain behalten wollen.

        Ein Domainwechsel mag auch ein Usecase sein, aber ein anderer. Und ein ziemlich seltener.

        … sondern relativ.

        <img src="/image/<?= htmlspecialchars($nFileName) ?>" alt="<?= $altText ?>">
        

        Alles ist relativ, meint Einstein?

        Das ist ein path-absolute-URL string. 😜

        🖖 Живіть довго і процвітайте

        --
        When the power of love overcomes the love of power the world will know peace.
        — Jimi Hendrix
      2. @@Rolf B

        Dafür sind die Kurz-Tags <?= ?> da

        Ich wünschte, es gäbe eine Kurzschreibweise nicht für <?php echo; ?>, sondern für <?php echo htmlspecialchars(); ?>. Die wäre dann wirklich hilfreich.

        🖖 Живіть довго і процвітайте

        --
        When the power of love overcomes the love of power the world will know peace.
        — Jimi Hendrix
        1. Ich wünschte, es gäbe eine Kurzschreibweise nicht für <?php echo; ?>, sondern für <?php echo htmlspecialchars(); ?>. Die wäre dann wirklich hilfreich.

          Finde heraus warum das Folgende ein Scherz ist:

          <?php
          /**
          * bewirkt einen sicheren Output in HTML
          **/
          function HSO(
              $string        = '',
              $flags         = ENT_QUOTES,
              $encoding      = false,
              $double_encode = true
          ) {
             if ( ! $encoding ) $encoding = mb_http_output();
              echo htmlspecialchars(
                  $string,
                  $flags,
                  $encoding,
                  $double_encode
               );
               return '';
          }
          ?>
          
          <h1>
          <?=HSO("'Was für ein Mist!'");?>
          </h1>