Sichere Dateiuploads mit PHP

4 06 2012

Stellen wir auf unserer Homepage den Besucher über einen Dateiupload die Möglichkeit zur Verfügung, eigene Dateien auf unseren Server zu übertragen, ist eine gewisse Vorsicht anzuraten. Immerhin möchten wir keinen ausführbaren Code auf unseren Server eingeschleust bekommen.

Um die übertragenen Dateien zu prüfen, könnten wir beispielsweise auf die Idee kommen, die $_FILES Variable auszulesen, die nach einem Upload vom Server gefüllt wird. Schauen wir uns diese doch anhand eines kleinen Beispiels einmal an.

<!-- Formular, um eine Datei hochzuladen -->
<form enctype="multipart/form-data" action="index.php" method="post">
Datei hochladen: <input name="datei" type="file" /><br />
<input type="submit" />
</form>

<?php
if (!empty($_FILES)){
	var_dump($_FILES);
}

Ausgabe:

Array
(
    [datei] => Array
        (
            [name] => avatar.jpg
            [type] => image/jpeg
            [tmp_name] => /tmp/phpLgZOUQ
            [error] => 0
            [size] => 8801
        )

)

Im vollständigen Beispiel sähe das dann in etwa so aus:

<?php
if (!empty($_FILES)){
	$upload_pfad = 'uploads/';	// Wo sollen die hochgeladenen Dateien abgelegt werden?
	$erlaubte_formate = array('image/gif', 'image/jpeg', 'image/png');	// Erlaubte Dateiformate
	$dateiname = $upload_pfad.basename($_FILES['datei']['name']);	// Dateiname inkl. Pfad

	echo '<p>Erkanntes Dateiformat: '.$_FILES['datei']['type'].'</p>';	// Ausgabe

	if (in_array($_FILES['datei']['type'], $erlaubte_formate)){	// Wenn es sich um eine datei.jpg handelt, gehen wir davon aus, dass es sich um eine Grafik handelt
		if(!move_uploaded_file($_FILES['datei']['tmp_name'], 'uploads/'.$_FILES['datei']['name'])) die('Konnte die Datei nicht hochladen');	// Datei in ihr Verzeichnis schieben
		echo '<img src="'.$dateiname.'" title="Hochgeladenes Bild" />';	// Ausgabe der Datei im Browser
	}
}

Ausgabe:

Erkanntes Dateiformat: image/jpeg

<img src="uploads/avatar.jpg" title="Hochgeladenes Bild" />

Nur leider kommen diese Werte vom Browser und lassen sich von daher relativ einfach manipulieren. Wir können uns darauf also nicht verlassen, da wir böswilligen Angreifern somit Tür und Tor öffnen. Die Unzuverlässigkeit erkennen wir deutlich daran, wenn wir unser Jpeg-Bild umbenennen in avatar.exe und den Upload damit testen.

Ausgabe:

Erkanntes Dateiformat: application/x-ms-dos-executable

An der Datei hat sich nichts geändert außer der Erweiterung. Es handelt sich also weiterhin um die gleiche Grafik, nur mit einem fehlerhaften Namenszusatz. Gefährlicher wird es, wenn beispielsweise eine EXE-Datei umbenannt wird, hier könnte einfach eine Bilddatei vorgetäuscht werden.

Somit erkennen wir schon, dass wir uns auch nicht einfach auf die Dateinamenserweiterung verlassen dürfen. Heißt die hochgeladene Datei schadcode.jpg, können wir keineswegs davon ausgehen, dass drin ist, was drauf steht.

<?php
if (!empty($_FILES)){
	$upload_pfad = 'uploads/';	// Wo sollen die hochgeladenen Dateien abgelegt werden?
	$erlaubte_formate = array('gif', 'jpg', 'png');	// Erlaubte Dateiformate
	$dateiname = $upload_pfad.basename($_FILES['datei']['name']);	// Dateiname inkl. Pfad

	$dateiinfo = pathinfo($_FILES['datei']['name']);
	$dateiformat = $dateiinfo['extension'];	// Auslesen der Dateierweiterung
	echo '<p>Erkanntes Dateiformat: '.$dateiformat.'</p>';	// Ausgabe

	if (in_array($dateiformat, $erlaubte_formate)){	// Wenn es sich um eine datei.jpg handelt, gehen wir davon aus, dass es sich um eine Grafik handelt
		if(!move_uploaded_file($_FILES['datei']['tmp_name'], 'uploads/'.$_FILES['datei']['name'])) die('Konnte die Datei nicht hochladen');	// Datei in ihr Verzeichnis schieben
		echo '<img src="'.$dateiname.'" title="Hochgeladenes Bild" />';	// Ausgabe der Datei im Browser
	}
}

Ausgabe:

Erkanntes Dateiformat: jpg

Auch dies ist keine geeignete Methode, denn die Erweiterung ist schnell verändert. Im Windows lässt sich zwar eine schadcode.jpg nicht starten, weil hier nur bestimmte Dateiformate ausgeführt werden, doch die meisten Webserver laufen unter einem Linux Derivat. Hier ist die Erweiterung vollkommen egal, es kommt nur darauf an, dass die Datei das Executable-Bit gesetzt hat. Im Beispiel sei verdeutlicht, dass auch eine .jpg Datei problemlos ausgeführt werden kann.

$ echo "echo Ich bin ausführbar" >schadcode.jpg
$ chmod u+x schadcode.jpg 
$ ./schadcode.jpg 
Ich bin ausführbar

Von daher sollten wir fremde Dateien niemals auf unserem System ausführen lassen. Idealerweise speichert man diese auch nicht innerhalb der vom Webserver lesbaren Dateistruktur (normalerweise htdocs), so dass diese gar nicht direkt vom Browser aus angesprochen werden können. Über unsere Skripte, die sich ja direkt auf dem Server befinden, sollten je nach Hoster auch andere Verzeichnisse ansprechbar sein. Auf ein Beispiel hierzu verzichte ich, da das etwas zu weit führen würde.

Um das Dateiformat einigermaßen sicher zu bestimmen, müssen wir den MIME Header der Datei lesen. Ab PHP >= 5.3 können wir dazu die finfo_file Funktion mit FILEINFO_MIME_TYPE nutzen. Für ältere PHP Versionen steht das Pendant mime_content_type zur Verfügung.

<?php
if (!empty($_FILES)){
	$upload_pfad = 'uploads/';	// Wo sollen die hochgeladenen Dateien abgelegt werden?
	$erlaubte_formate = array('image/gif', 'image/jpeg', 'image/png');	// Erlaubte Dateiformate
	$dateiname = $upload_pfad.basename($_FILES['datei']['name']);	// Dateiname inkl. Pfad

	$finfo = finfo_open(FILEINFO_MIME_TYPE);	// Gib den MIME Typ zurueck
	if ($finfo !== FALSE && !empty($finfo)){
	   	$dateiformat = finfo_file($finfo, $_FILES['datei']['tmp_name']);
		finfo_close($finfo);
	} else die('Fileinfo Datenbank konnte nicht geoeffnet werden');

	echo '<p>Erkanntes Dateiformat: '.$dateiformat.'</p>';	// Ausgabe

	if (in_array($dateiformat, $erlaubte_formate)){	// Dieser Dateityp entspricht unseren Vorgaben
		if(!move_uploaded_file($_FILES['datei']['tmp_name'], 'uploads/'.$_FILES['datei']['name'])) die('Konnte die Datei nicht hochladen');	// Datei in ihr Verzeichnis schieben
		echo '<img src="'.$dateiname.'" title="Hochgeladenes Bild" />';	// Ausgabe der Datei im Browser
	}
}

Ausgabe:

Erkanntes Dateiformat: image/jpeg
<img src="uploads/avatar.jpg" title="Hochgeladenes Bild" />

Nun sollte man sich auch nicht auf den Mime-Typ alleine verlassen. So würde nämlich auch eine schadcode.exe Datei akzeptiert werden, wenn nur der Mime-Typ passt. Laden wir doch einfach unsere avatar.exe hoch.

Erkanntes Dateiformat: image/jpeg
<img src="uploads/avatar.exe" title="Hochgeladenes Bild" />

Von daher sollte man die Erweiterung anhand des erkannten Typs stets selbst setzen, um absichtliche wie auch unabsichtliche Nutzerfehler zu vermeiden.

<?php
if (!empty($_FILES)){
	$upload_pfad = 'uploads/';	// Wo sollen die hochgeladenen Dateien abgelegt werden?
	$erlaubte_formate = array(
		'image/gif' => 'gif',
		'image/jpeg' => 'jpg',
		'image/png' => 'png');	// Erlaubte Dateiformate. Im multidimensionalen Array sind nun auch die zugehoerigen Dateierweiterungen angegeben

	$dateiname = $upload_pfad.pathinfo($_FILES['datei']['name'], PATHINFO_FILENAME);	// Mit pathinfo holen wir nur den Dateinamen ohne Erweiterung

	$finfo = finfo_open(FILEINFO_MIME_TYPE);	// Gib den MIME Typ zurueck
	if ($finfo !== FALSE && !empty($finfo) > 0){
	   	$dateiformat = finfo_file($finfo, $_FILES['datei']['tmp_name']);
		finfo_close($finfo);
	} else die('Konnte das Dateiformat nicht erkennen');

	echo '<p>Erkanntes Dateiformat: '.$dateiformat.'<br />';	// Ausgabe

	if (isset($erlaubte_formate[$dateiformat])){	// Existiert ein Eintrag mit dem Key?
		$dateiname .= '.'.$erlaubte_formate[$dateiformat];	// Haenge die Erweiterung an den Dateinamen an

		echo 'Ursprünglicher Dateiname: '.$_FILES['datei']['name'].'<br />';
		echo 'Aktueller Name: '.basename($dateiname).'</p>';

		if(!move_uploaded_file($_FILES['datei']['tmp_name'], $dateiname)) die('Konnte die Datei nicht hochladen');	// Datei in ihr Verzeichnis schieben
		echo '<img src="'.$dateiname.'" title="Hochgeladenes Bild" />';	// Ausgabe der Datei im Browser
	}
}

Die Ausgabe, wenn wir wieder unsere avatar.exe hochladen:

Erkanntes Dateiformat: image/jpeg
Ursprünglicher Dateiname: avatar.exe
Aktueller Name: avatar.jpg

<img src="uploads/avatar.jpg" title="Hochgeladenes Bild" />

Abschließend sei noch auf getID3() hingewiesen. Dieses umfangreiche Skript liest die verschiedensten Multimedia-Formate ein und liefert neben den Header Informationen noch viele weitere nützliche Informationen. In unserem Beispiel sähe der Einsatz dann so aus:

<?php
if (!empty($_FILES)){
	require_once('getid3/getid3.php');	// getID3() einbinden
	$getID3 = new getID3;

	$upload_pfad = 'uploads/';	// Wo sollen die hochgeladenen Dateien abgelegt werden?
	$erlaubte_formate = array('image/gif', 'image/jpeg', 'image/png');	// Erlaubte Dateiformate

	$dateiname = $upload_pfad.pathinfo($_FILES['datei']['name'], PATHINFO_FILENAME);	// Mit pathinfo holen wir nur den Dateinamen ohne Erweiterung

	$dateiinfo = $getID3->analyze($_FILES['datei']['tmp_name']);
	var_dump($dateiinfo);

	echo '<p>Erkanntes Dateiformat: '.$dateiinfo['mime_type'].'<br />';	// Ausgabe

	if (in_array($dateiinfo['mime_type'], $erlaubte_formate)){	// Dieser Dateityp entspricht unseren Vorgaben
		$dateiname .= '.'.$dateiinfo['fileformat'];	// Haenge die Erweiterung an den Dateinamen an

		echo 'Ursprünglicher Dateiname: '.$_FILES['datei']['name'].'<br />';
		echo 'Aktueller Name: '.basename($dateiname).'</p>';

		if(!move_uploaded_file($_FILES['datei']['tmp_name'], $dateiname)) die('Konnte die Datei nicht hochladen');	// Datei in ihr Verzeichnis schieben
		echo '<img src="'.$dateiname.'" title="Hochgeladenes Bild" />';	// Ausgabe der Datei im Browser
	}
}

Zur besseren Verdeutlichung erfolgt zunächst die Ausgabe des von getID3() gelieferten Arrays mit den Dateiinformationen. Danach folgt unsere normale Ausgabe. Da auch die Erweiterung geliefert wird, müssen wir diese nicht mehr selbst definieren:

array(11) {
  ["GETID3_VERSION"]=>
  string(14) "1.9.3-20111213"
  ["filesize"]=>
  int(8801)
  ["filename"]=>
  string(9) "phpb1p7Qd"
  ["filepath"]=>
  string(4) "/tmp"
  ["filenamepath"]=>
  string(14) "/tmp/phpb1p7Qd"
  ["avdataoffset"]=>
  int(0)
  ["avdataend"]=>
  int(8801)
  ["fileformat"]=>
  string(3) "jpg"
  ["video"]=>
  array(7) {
    ["dataformat"]=>
    string(3) "jpg"
    ["lossless"]=>
    bool(false)
    ["bits_per_sample"]=>
    int(24)
    ["pixel_aspect_ratio"]=>
    float(1)
    ["resolution_x"]=>
    int(72)
    ["resolution_y"]=>
    int(100)
    ["compression_ratio"]=>
    float(0.4074537037037)
  }
  ["encoding"]=>
  string(5) "UTF-8"
  ["mime_type"]=>
  string(10) "image/jpeg"
}

Erkanntes Dateiformat: image/jpeg
Ursprünglicher Dateiname: avatar.exe
Aktueller Name: avatar.jpg

<img src="uploads/avatar.jpg" title="Hochgeladenes Bild" />

Ist das jetzt wirklich sicher? Einigermaßen, doch muss für die maximale Sicherheit immer der maximale Aufwand betrieben werden. Mit Erkennung des Mime-Headers und idealerweise der Ablage der Dateien außerhalb des Web-Roots sollte man zumindest einigermaßen auf der sicheren Seite sein. Sicherer immerhin, als sich auf die durch $_FILES oder getimagesitze gelieferten Informationen zu verlassen. Letzteres hat sich in der Hinsicht in der Vergangenheit immer wieder durch seine Angreifbarkeit disqualifiziert.

Advertisements




Aufsetzen von Subdomains mit XAMPP

24 05 2012

Das XAMPP Paket stellt eine gute Alternative zur Installation der einzelnen Webserverkomponenten dar, wenn man seine dynamische Homepage auf dem heimischen Computer testen will. Das vorkonfigurierte System bedarf nahezu keiner Konfiguration und kann im Auslieferungszustand im Grunde schon genutzt werden. Dazu lädt man sich einfach bei den Apache Friends das geeignete Archiv für sein System herunter. Dann extrahiert man dieses in den gewünschten Ordner, unter Linux bietet sich hierzu /opt an.
tar xvfz xampp-linux-1.7.7.tar.gz -C /opt

Nach  dem Start mittels
[installationspfad]/lampp start
kann man seinen Browser auf localhost verweisen und sollte schon die Testseite seines funktionierenden Servers sehen.

Auch das Einrichten von virtuellen Hosts ist nur wenig schwieriger. Hat man mehrere Projekte auf seinem Computer, bietet es sich an, diese aufzutrennen. So möchte ich beispielsweise neben RamTatTa, das auf localhost läuft auch noch die Punkkonzerte Datenbank einrichten. Dies soll unter der Subdomain punkkonzerte.localhost geschehen. Das Verzeichnis mit den Dateien existiert unter ~/htdocs/Punkkonzerte/.

Dazu editieren wir zunächst unsere hosts Datei und erweitern sie um den entsprechenden Eintrag
sudo vi /etc/hosts

127.0.0.1    localhost

# Dieser Eintrag kommt neu hinzu
127.0.0.1    punkkonzerte.localhost

Jetzt fügen wir unserer VHosts Datei einen Eintrag hinzu. Hier sollten wir schon zwei Beispiel-Einträge finden, die wir löschen (ängstliche Naturen können die Zeilen natürlich auch auskommentieren). Die Datei sollte nun diese Zeilen beinhalten:
sudo vi /opt/lampp/etc/extra/httpd-vhosts.conf

NameVirtualHost *:80
<VirtualHost *:80>
    ServerAdmin aaaaaprvdgrwwelt@example.org
    DocumentRoot /home/aaaaaprvdgrwwelt/htdocs/RamTatTa
    ServerName localhost
    ErrorLog logs/error_log
    CustomLog logs/access_log common
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin aaaaaprvdgrwwelt@example.org
    DocumentRoot /home/aaaaaprvdgrwwelt/htdocs/Punkkonzerte
    ServerName punkkonzerte.localhost 
    ErrorLog logs/punkkkonzerte-error_log
    CustomLog logs/punkkonzerte-access_log common
</VirtualHost>

ServerAdmin sollte die eigene E-Mail Adresse sein. Auf dem lokalen System kann man das aber vernachlässigen.
DocumentRoot gibt an, in welchem Verzeichnis sich die Dateien des Web-Projektes befinden
ServerName konfiguriert den Namen der Subdomain
ErrorLog definiert den Namen der Fehlerdatei
CustomLog definiert den Namen der Zugriffs-Logdatei

Als letzten Schritt müssen wir Apache nur noch mitteilen, dass er die VHosts Datei auch einlesen soll. Dies geschieht mittels der httpd.conf, in der wir die Kommentarzeichen bei der entsprechenden Zeile entfernen.
sudo vi /opt/lampp/etc/httpd.conf

# Virtual hosts
Include etc/extra/httpd-vhosts.conf

Das war es auch schon. Nur noch XAMPP neu starten, damit Apache seine Konfiguration einliest (lampp restart) und schon haben wir eine schöne neue Subdomain. Diese Schritte können so natürlich noch für weitere virtuelle Hosts durchgeführt werden.





HTML5 MP3 Player für die Homepage

20 05 2012

Im Beitrag „Flash MP3 Player für die Homepage“ hatte ich einige Audio Player auf Flash Basis vorgestellt. Da Flash immer mehr aus der Mode kommt und hoffentlich bald gänzlich durch HTML5 Techniken ersetzt werden kann, wollen wir doch einen Blick auf entsprechende Umsetzungen werfen. Einige davon bieten einen Fallback auf Flash, da noch nicht jeder Browser HTML5 in vollem Umfang unterstützt.

Name: audio.js
Homepage: http://kolber.github.com/audiojs/
Lizenz: MIT License
Beschreibung: Java-Library, die den <audio> Tag für Browser nutzt, die diesen schon unterstützen. Ist dies nicht der Fall, wird auf Flash zurück gegriffen.


Name: HTML5 Music Player
Homepage: http://www.codebasehero.com/2011/07/html5-music-player-updated/
Lizenz: MIT License
Beschreibung: Kostenloser Ableger der MediaBox, der auf jQuery aufsetzt.


Name: jPlayer
Homepage: http://jplayer.org/
Lizenz: GPL / MIT
Beschreibung: Wohl der bekannteste Vertreter seiner Art. Nutzt die jQuery Bibliothek als Basis. Nicht nur als Audio-, sondern gleichzeitig auch als Video-Player einsetzbar.


Name: MediaElement.js
Homepage: http://mediaelementjs.com/
Lizenz:
Beschreibung: Audio- und Videoplayer, der auf Flash oder Silverlight zurück fällt, wenn die HTML5 Funktionen nicht zur Verfügung stehen.


Name: MooTools HTML5 Audio Player
Homepage: http://simulacre.org/mootools-html5-audio-player/
Lizenz:
Beschreibung: Ein Player, der auf die MooTools Bibliothek zurückgreift. Scheint seit dem Alpha-Stadium nicht mehr weiter entwickelt zu werden.


Name: SoundManager 2
Homepage: http://www.schillmania.com/projects/soundmanager2/
Lizenz: BSD License
Beschreibung: Optionenreicher Player mit Flash Fallback. Kann auch genutzt werden, um einzelne MP3 Links auf der Webseite wiederzugeben.


Name: Speakker
Homepage: http://www.speakker.com/
Lizenz: GNU General Public Licens
Beschreibung: Schicker Player, der als Nebenprojekt des Projekktor Video Players entstanden ist.





Verwendung der Klasse jquery-oembed-all

13 05 2012

Im Artikel „Medien einbinden mittels oEmbed“ hatte ich beschrieben, wie man mit PHP auf die oEmbed Daten von externen Anbietern zugreift. Nun macht das nur in eher wenigen Fällen Sinn, dies per PHP zu tun. Möchte man dynamisch die Daten beim Laden seiner Seite abgreifen, verzögert sich dies, bis der externe Dienst eine Antwort schickt. Steht dieser gerade nicht zur Verfügung oder hat Performanceprobleme, wirkt sich das konkret auf die Ladegeschwindigkeit der eigenen Seite aus. Nun könnte man die Daten auch einmalig abgreifen und in der eigenen Datenbank speichern. Was aber, wenn der Anbieter seinen Einbettungscode ändert?

Sinnvoller ist es, die eigene Seite zu laden und erst wenn diese angezeigt wird mittels JavaScript die externen Informationen im Nachhinein abzugreifen. Somit erübrigen sich die eben genannten Nachteile. Mit jquery-oembed-all existiert eine gute Klasse für jQuery, mit der sich genau dies bewerkstelligen lässt. Die Klasse ist ein Fork des in jüngster Vergangenheit vom Entwickler etwas stiefmütterlich behandelten  jquery-oembed, die im Gegensatz zum Original nicht auf den offensichtlich eingestellten Dienst oohembed angewiesen ist und, sollte oEmbed nicht zur Verfügung stehen alternative Methoden zur Einbindung nutzt.

Leider mangelt es jquery-oembed-all an einer Dokumentation, weshalb ich hier einen kurzen Überblick über die Funktionen geben möchte. Beginnen wir mit einem einfachen Beispiel. Dieses platziert das einzubindende Objekt in das Div „container“.

<html>
<head>
<!-- jQuery laden -->
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<!-- die oembed-all Klasse laden -->
<script type="text/javascript" src="jquery.oembed.js"></script>
</head>

<body>
<script type="text/javascript">
// Platziere das Objekt aus .oembed im Element mit der id "container"
 $(document).ready(function() {
    $("#container").oembed("http://vimeo.com/1084537");
});
</script>
<!-- An dieser Position wird das Video angezeigt -->
<div id="container"></div>
</body>
</html>

Ergebnis:

Nun haben wir nicht nur ein Objekt zur Einbindung, sondern möchten neben dem Video noch ein Bild von Flickr anzeigen. Das zweite Beispiel platziert für jeden Link mit der Klasse „oembed“ das entsprechende Objekt.

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="jquery.oembed.js"></script>
</head>

<body>
<script type="text/javascript">
$(document).ready(function() {
 // Suche in jedem Element a mit der Klasse "oembed"
 $("a.oembed").oembed();
});
</script>
<div><a class="oembed" href="http://www.flickr.com/photos/kl/2423315026/">Flickr Bild</a></div>
<div><a class="oembed" href="http://vimeo.com/1084537">Vimeo Video</a></div>
</body>
</html>

Ergebnis:

Es können verschiedene Optionen angewendet werden.
autoplay (true / false): Soll ein Video automatisch gestartet werden?
maxWidth: Die maximale Breite für das Objekt
maxHeight: Die maximale Höhe für das Objekt
embedMethod: Wie soll das Objekt eingebunden werden?
– + append: Setze das Objekt unter den Link
– + fill: Ersetze den Link durch das Objekt, erhalte aber die Klasse
– + replace: Ersetze den Link und die Klasse durch das Objekt

Zur Veranschaulichung der Optionen folgt unser nächstes Beispiel. Es ist anzumerken, dass globale Optionen gesetzt werden können, die dann für jeden Dienst gelten, aber auch pro Dienst eigene Einstellungen möglich sind.

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="jquery.oembed.js"></script>
</head>

<body>
<script type="text/javascript">
    $(document).ready(function() {
    $(".oembed").oembed(null, {
        // Globale Optionen
        embedMethod: "append", // Haenge an
        maxWidth: 640, // Maximale Breite: 640 Pixel
        maxHeight: 480, // Maximale Hoehe: 480 Pixel
        vimeo: { // Diese Optionen gelten ausschliesslich fuer den Anbieter Vimeo
        	autoplay: true, 
        	maxWidth: 400, 
        	maxHeight: 400
        }
    });
});
</script>
<div><a class="oembed" href="http://www.flickr.com/photos/kl/2423315026/">Flickr Bild</a></div>
<div><a class="oembed" href="http://vimeo.com/1084537">Vimeo Video</a></div>
</body>
</html>

Das Video wurde auf die angegebene Maximalgröße verkleinert. Da die Einbettungsmethode „append“ verwendet wurde, werden die Objekte an die Links angehängt.

Mit der Methode „fill“ wird zwar der Link ersetzt, die Klasse .oembed bleibt allerdings erhalten. Die Klassen sind im Screenshot zur Verdeutlichung angezeigt.

„replace“ letztendlich ersetzt den kompletten Link inklusive seiner Klasse durch das einzubettende Objekt. Dies erkennt man am Besten im Vergleich der Klassen-Namen.





Flash MP3 Player für die Homepage

6 09 2011

Für RamTatTa war ich auf der Suche nach einem geeigneten MP3 Player, mit dem möglichst komfortabel die Musikstücke und Interviews im MP3 Format wiedergegeben werden können. Zunächst fiel die Wahl auf den EP Player, der zwar nicht kostenlos ist, aber einen guten Funktionsumfang für den Preis von 20 Euro bietet. Das Problem ist, dass die Lizenz immer nur für eine Domain gilt und diese auch nicht mehr anpassbar. Da ich die Beta-Version unter anderer Domain laufen habe, wurde mir hier immer ein Registrierungs-Hinweis angezeigt, was auf Dauer doch sehr nervig war. Und kaufen wollte ich diesen für die Test-Domain auch nicht.

Aus diesem Grund habe ich mich dann auf die Suche nach einer geeigneten Alternative gemacht. Dabei bin ich im Laufe der Zeit auf diese Player gestoßen, die einen mehr oder weniger guten Eindruck machen.


Name: 1 Bit Audio Player
Homepage: http://1bit.markwheeler.net/
Lizenz: Kostenlos, Open Source
Hinweis: Wird seit 2008 nicht mehr weiterentwickelt
Features:
– Bietet nur einen Button, mit dem im HTML verlinkte MP3 Dateien wiedergegeben werden können


Name: Dewplayer
Homepage: http://www.alsacreations.fr/dewplayer-en
Lizenz: Creative Commons auch für kommrezielle Nutzung (Ausnahme Weiterverkauf)
Features:
– Verschiedene Design, hierfür wird allerdings jeweils eine eigene Flash-Datei benötigt
– Javascript-Kontrolle
– Playliste


Name: EP Player
Homepage: http://www.epplayer.com/
Lizenz: Kommerziell, 19,99 Euro pro Domain
Features:
– Verschiedene Skins werden mitgeliefert
– Javascript-Kontrolle
– Playliste


Name: FLAMPlayer
Homepage: http://www.flamplayer.com/
Lizenz: Kostenlos, mit Copyright-Vermerk
Hinweis: In meinen Augen früher der beste Player, wird leider seit 2007 nicht mehr weiterentwickelt.
Features:
– Verschiedene Skins möglich
– Playliste
– Daten werden in einer MySQL Datenbank gespeichert


Name: Flash MP3 Player
Homepage: http://www.flashmp3player.org/
Lizenz: Creative Commons mit Link zum Hersteller, eine Entfernung des Copyright-Hinweises ist für 19 Dollar möglich
Features:
– Verschiedene Skins möglich
– Scannt ein Verzeichnis nach MP3 Dateien und bindet diese automatisch in die Playliste ein
– Autoresume (d.h. speichert die aktuelle Position und spielt dort nach einem Seitenwechsel weiter)


Name: Flowplayer
Homepage: http://flowplayer.org/plugins/streaming/audio.html
Lizenz: Kostenlos unter GPL, solange der Copyright-Hinweis im Player verbleibt. Entfernen des Copyright-Hinweises ab 69 Euro
Features:
– Eigentlich ein Video-Player, kann aber auch zur MP3 Wiedergabe verwendet werden
– Unterstützt Secure Streaming, um sicher über http und lighttpd Server zu streamen
– Unterstützt Streaming über das RTMP Protokoll


Name: JW Player
Homepage: http://www.longtailvideo.com/players/
Lizenz: Kostenlos, Einsatz auf kommerziellen Webseiten nur mit der Pro-Version ab 59 Euro
Features:
– Eigentlich ein Video-Player, kann aber auch zur MP3 Wiedergabe verwendet werden
– Nutzt Flash oder HTML5 Technologien
– Skins
– Plugins


Name: MP3 Player
Homepage: http://flash-mp3-player.net/
Lizenz: Kostenlos
Features:
– Verschiedene Designs, allerdings wird nur die „Maxi“-Version weiter gepflegt
– Javascript-Kontrolle


Name: XSPF Web Music Player
Homepage: http://musicplayer.sourceforge.net/
Lizenz: Kostenlos
Hinweis: wird seit 2006 nicht mehr weiterentwickelt
Features:
– Slim, Extended und Button Version
– Nutzt das XML Shareable Playlist Format


Weitere MP3 Player:

DNeX FMP256 (gibt es in einer abgespeckten kostenlosen und einer erweiterten kommerziellen Version)

Hoover Web Design Flash Music Player

Website Music Player (Download)

Zanorg Player (spielt nur eine einzelne Datei ab)





elRTE Farben verändern

19 02 2011

Ein WYSIWYG Editor ist schon etwas Schönes. Man kann den Besuchern seiner Webseite einen Editor bieten, der sich ohne BBCode oder HTML fast schon wie eine normale Desktop-Textverarbeitung bedienen lässt. Das Problem mit dem ich immer zu kämpfen habe ist, das Standard-Design entsprechend an meine Seite anzupassen. Gerade experimentiere ich mit elRTE und da die CSS Definitionen weit verzweigt sind eine Kurz-Liste zur schnellen Anpassung der grundsätzlichen Farben. Will man die Pop-Ups anpassen, kann man es sich auch einfach machen und hier ein vorgefertigtes Theme herunterladen. Das gilt aber auch wirklich nur für die Dialog-Boxen.

Editor-Hintergrund
In css/elrte-inner.css hinzufügen:
body{ background-color: #000; }

Alle weiteren Werte werden in der css/elrte.min.css angepasst.

Hintergrund der Buttonleiste
.el-rte .toolbar{background-color:#eee;padding:3px 7px 2px 7px;border:1px solid #ccc;white-space:normal;}

Rahmen der Buttonleiste
.el-rte .toolbar{background-color:#eee;padding:3px 7px 2px 7px;border:1px solid #ccc;white-space:normal;}

Rahmen der Buttons
.el-rte .toolbar ul li{display:inline-block;display:-moz-inline-stack;display:inline-block;height:22px;width:22px;vertical-align:top;zoom:1;*display:inline;margin:1px 1px;padding:0;background:url('../images/elrte-toolbar.png') no-repeat;border:1px solid #ccc;}

Rahmen der Buttons beim Mouseover
.el-rte .toolbar ul li.hover{border:1px solid #54b9bf;}

Rahmen und Hintergrund der aktiven (gedrückten) Buttons
.el-rte .toolbar ul li.active{background-color:#c3dbef;border:1px solid #fff;}

Rahmen des Editors
.el-rte .workzone{border:1px solid #eee;border-top:none;height:400px;overflow:hidden;}

Hintergrundfarbe der Fußzeile
.el-rte .statusbar{height:21px;padding:0 9px;font:11px/21px 'monaco','andale mono','lucida console',monospace;background-color:#eee;border-top:1px solid #ccc;border-top:none;}

Hintergrundfarbe der unteren Tabulatoren
.el-rte .tabsbar .tab{float:left;margin-right:2px;padding:6px 17px;font-size:.82em;font-weight:bold;color:#777;text-align:center;border:1px solid #eee;border-top:none;background:#fff;cursor:default;}

Hintergrundfarbe der aktiven unteren Tabulatoren
.el-rte .tabsbar div.active{background:#eee;color:#444;}

Breite / Höhe ändern
Dafür gibt es die Optionen width und height. Allerdings weicht zumindest die Angabe für die Breite bei mir um 10 Pixel von der Breite meiner sonstigen Formular-Elemente ab. Mag allerdings sein, dass das mit meiner eigenen CSS-Datei zusammen hängt.
var opts = {
width  : 400,
height : 250,
...
}





BOM, Webseitenanzeige kaputt

22 12 2010

Ich stand vor einem Problem, das sich mir nicht ganz erschloss. Die ganze Zeit wurde meine Webseite korrekt angezeigt. Dann wollte ich eigentlich nur eine kurze Änderung vornehmen, wodurch die komplette Seite um eine Zeile nach unten verschoben wurde. Ich konnte mir wirklich nicht vorstellen, woran das liegen sollte, hatte ich doch nur einen Text geringfügig geändert. Also kein Grund für die Darstellung, gleich beleidigt zu spielen.

Erst eine nähere Untersuchung der aus PHP Skripten generierten HTML Seite machte klar, da ist etwas mit dem Header passiert. Was der grafische Editor nicht anzeigte, im vi zeigte sich ein Tag namens <feff>

<feff><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


FileFormat.info
erklärt, dass es sich dabei um die Byte Order Mark von UTF-8 Dokumenten handelt. Eigentlich eine praktische Sache, doch Firefox kommt mit der Anzeige nicht korrekt. Die einfache Entfernung der BOM für die Template Datei brachte die Lösung für ein Problem, das mir wirklich einiges Kopfzerbrechen beschert hatte.