PHP rocks! wünscht allen Mitgliedern einen guten Rutsch ins neue Jahr 2017 !!!
Hinweis: Das Forum zieht um! Um keine Datenverluste zu haben, schalten wir zwecks Übernahme der Daten das Forum am Sonntag, den 24.04.2016 um ca. 21:00 Uhr offline und passen anschliessend die DNS-Einträge an.
www.php-rocks.de wird euch dann nach den Aktualisierungen der DNS-Server wieder wie gewohnt uneingeschränkt zur Verfügung stehen.
Danke für euer Verständnis!

Hallo, Gast
Du musst dich registrieren bevor du auf unserer Seite Beiträge schreiben kannst.

Benutzername/E-Mail:
  

Passwort
  





Durchsuche Foren

(Erweiterte Suche)

Foren-Statistiken
» Mitglieder: 290
» Neuestes Mitglied: zacharymurphy
» Foren-Themen: 169
» Foren-Beiträge: 899

Komplettstatistiken

Aktive Themen
PHPMailer Pfad wird nicht...
Forum: PHP Basics
Letzter Beitrag: Arne Drews
23.08.2022, 21:07
» Antworten: 5
» Ansichten: 2.726
PHP 8.1: Endlich Enums in...
Forum: PHP Basics
Letzter Beitrag: Arne Drews
22.04.2021, 16:55
» Antworten: 1
» Ansichten: 2.622
Einfache Template Engine
Forum: PHP Template Engines
Letzter Beitrag: Arne Drews
22.04.2021, 16:49
» Antworten: 4
» Ansichten: 10.916
OAuth - Should I "scrambl...
Forum: Off Topic
Letzter Beitrag: Till
05.01.2020, 04:55
» Antworten: 0
» Ansichten: 7.751
"Invisible" Captcha
Forum: PHP Basics
Letzter Beitrag: Arne Drews
11.12.2019, 15:00
» Antworten: 5
» Ansichten: 10.293
Projektvorstellung - Test...
Forum: Off Topic
Letzter Beitrag: Till
22.11.2019, 20:03
» Antworten: 3
» Ansichten: 5.576
POST/GET routes deklarier...
Forum: PHP Basics
Letzter Beitrag: Till
14.11.2019, 19:44
» Antworten: 2
» Ansichten: 4.608
PHPMailer
Forum: PreComposed
Letzter Beitrag: Arne Drews
20.10.2019, 12:44
» Antworten: 6
» Ansichten: 8.449
Twig TemplateEngine
Forum: PreComposed
Letzter Beitrag: Arne Drews
29.08.2019, 14:21
» Antworten: 0
» Ansichten: 3.279
SwiftMailer
Forum: PreComposed
Letzter Beitrag: Arne Drews
28.08.2019, 10:19
» Antworten: 0
» Ansichten: 3.455

 
  Einfache SEO-friendly URL's umsetzen
Geschrieben von: Arne Drews - 15.05.2015, 21:49 - Forum: Tutorials - Keine Antworten

Was versteht man unter Suchmaschinen optimierten URL's?
Unter einer Suchmaschinen optimierten ( SEO-friendly ) URL versteht man im allgemeinen eine URL mit prägnanten keywords für Suchmaschinen á la Google & Co.
Kurz gesagt, können wir unsere Seiten bereits mit Hilfe der URL für die großen Suchmaschinen interessant machen.

Google bspw. wertet eine Seite mit prägnanten Suchbegriffen höher in der Ergebnisliste, als die Seiten, auf denen die Suchbegriffe "nur" im Content enthalten sind. Natürlich dürfen wir den Content nicht vernachlässigen, denn die URL ist nur einer von vielen Faktoren für die Ergebnisbewertung, wenn auch ein sehr wichtiger.


Der Aufbau unserer SEO-friendly URL
Wir nehmen für dieses kleine Tutorial mal an, daß wir eine Seite unserer Website speziell für PHP-Tutorials haben und diese für die Suchmaschinen optimieren wollen.
Uns interessiert hier erstmal nur der Aufbau der URL.

Nehmen wir also an, wir legen folgende URL für ein Tutorial wie dieses fest:

Code:
http://www.example.com/php-tutorials/seo-friendly-urls-mit-php.html
Damit haben wir eine URL, die über prägnante Suchbegriffe verfügt. Angezeigt werden soll allerdings eine Seite, die in unserem Webspace hier liegt:
Code:
/view/tutorials/seo-friendly-urls-mit-php.php


Muß meine Webstruktur entsprechend der URL aufgebaut sein?
Nein, natürlich nicht. Der ganze Trick ist einfach, die Anfrage intern umzuleiten und den entsprechenden Content vorzublenden. Was sich so einfach anhört, ist in Wirklichkeit auch beinahe so leicht, wie es sich liest.
Um das entsprechend umzusetzen, reicht prinzipiell eine index.php. In größeren Projekten kommt auch eine bootstrap.php zum Einsatz, aber das soll für dieses Tutorial mal ignoriert werden.
Uns reicht wie gesagt fürs erste eine index.php im Webroot.

Der Webserver
Hinweis
Der folgende Abschnitt bezieht sich auf einen Apache HTTP Server ab Version 2.2 mit aktiviertem mod_rewrite! Sollte die Datei .htaccess nicht existeren, muß diese zuvor angelegt werden.
Die erste wichtige Aufgabe übernimmt der Webserver, indem er die Anfrage intern umleitet. Dazu haben wir beim Apache zwei Möglichkeiten. Eine weit verbreitete und schlanke Lösung, die auch in großen Frameworks Anwendung findet bietet uns das mod_rewrite Modul:
Code:
RewriteEngine On
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^ index.php [QSA,L]
Diese Zeilen tragen wir in die .htaccess im Webroot ein. Diese sorgen für die interne Umleitung.
Im Grunde sind die letzten drei Zeilen für uns interessant. Diese teilen dem Webserver mit, daß alle Anfragen, die physikalisch nicht als Datei oder Verzeichnis existieren auf die index.php geleitet werden.

Aber es gibt da noch was: FallbackResource
Mit FallbackResource teilen wir dem Webserver mit, daß es einen sog. Fallback für nicht existente Dateien und Verzeichnisse gibt. Der Webserver nutzt diese FallbackResource und umgeht gleichzeitig einen 404. Im Prinzip also genau das, was wir oben gemacht haben, nur in einer Anweisung.

FallbackResource ist weniger bekannt/verbreitet, wie die erste Variante, aber meiner Meinung nach die sinnvollere und vermutlich auch die performantere Lösung.

Lange Rede, kurzer Sinn: Das was unsere erste Variante macht, erreichen wir ebenfalls stattdessen auf diese Weise:
Code:
FallbackResource disabled
FallbackResource /index.php
Die erste Zeile sorgt dafür, daß vererbte FallbackResource-Einstellungen aus dem Elternverzeichnis deaktiviert werden. Diese ist nur wichtig, wenn es sich nicht gerade um die htaccess im Webroot handelt. Im Normalfall reicht die zweite Zeile alleinstehend.
Hinweis
Die FallbackResource Direktive liefert uns der Apache ab Version 2.2.16. Die Direktive ist allerdings kein Bestandteil des mod_rewrite Modul, sondern dem mod_dir Modul. Ich denke, ein Grund, warum es unbekannter ist, denn jeder der sich mit URL-Rewriting befasst, liest sich assoziativ verständlicher Weise zuerst mal in die Möglichkeiten des mod_rewrite Moduls ein, wo FallbackResource nicht zu finden ist. Den Parameterwert disabled gibt es für FallbackResource übrigens ab der Version 2.2.24 des Apache HTTP Servers!


...und weiter gehts!
Welche der beiden Varianten ihr oben verwendet spielt für den weiteren Verlauf des Tutorials keine Rolle, ihr habt da vollkommene Entscheidungsfreiheit.

Wir gehen also für den Moment davon aus, daß das Verzeichnis php-tutorials/ aus unserer URL nicht existiert.
Die Anfrage landet also aufgrund unserer .htaccess Konfiguration aus dem oberen Abschnitt in der index.php.


Und wie gebe ich nun den richtigen Content aus?
Nun, auch das ist relativ einfach. PHP verwaltet Server-Variablen in dem Superglobalen Array $_SERVER, auf das wir nun zugreifen können.
Unsere Information finden wir unter dem Index REQUEST_URI. Diesen werten wir aus und laden den entsprechenden Content einfach in die index.php.

Es gibt natürlich verschiedene Möglichkeiten dies umzusetzen, für unser kleines Tutorial soll eine kleine switch ... case Fallentscheidung genügen:
PHP-Code:
$aPath pathinfo$_SERVER['REQUEST_URI'] );


switch ( 
$aPath['dirname'] ) {

 
   case '/php-tutorials':
 
       $sIncludePath '/view/tutorials/';
 
       break;
 
   default:
 
       $sIncludePath '/view/content/';
 
       break;

}


include_once 
__DIR__ $sIncludePath $aPath['filename'] . '.php'
Die Funktion pathinfo() versucht aus dem übergebenen Pfad Details zum Pfad ( hier $_SERVER['REQUEST_URI'] ) zu extrahieren und stellt diese dann in den Elementen dirname, basename, extension und filename zur Verfügung. Uns sollen im Moment nur dirname und filename dabei interessieren. Konnten die Informationen gesammelt werden finden wir in $aPath['dirname'] den Verzeichnispfad ( in unserem Beispiel: php-tutorials ) und in $aPath['filename'] den reinen Dateinamen ohne(!) Erweiterung ( hier: seo-friendly-urls-mit-php ).

Der Code macht also nun nichts weiter, als das Verzeichnis auszuwerten und die gewünschte Datei per include_once einzubinden.

Wie man sieht, es ist relativ einfach SEO-friendly URL's in eigenen Projekten zu verwenden.
Der PHP-Teil ist je nach Projekt sicher anders umgesetzt, aber zur Erklärung im Rahmen dieses Tutorials soll das ausreichend sein.

Drucke diesen Beitrag

  Verzeichnisse rekursiv iterieren mit der SPL
Geschrieben von: Arne Drews - 14.05.2015, 17:11 - Forum: Tutorials - Keine Antworten

Was bezweckt dieses Tutorial
In größeren Projekten kann es hilfreich sein, ab einem bestimmten Einstiegspunkt die komplette Verzeichnisstruktur inklusive der Datei-Informationen rekursiv bspw. in einem Array vorzuhalten. Ich möchte hier kurz zeigen, wie das mit Hilfe der SPL ( Standard PHP Library ) möglich ist.

Da die SPL über eine Auswahl an Iteratoren verfügt, brauchen wir uns um die Rekursion innerhalb der Verzeichnisstruktur keine Gedanken machen, geschweige denn dafür sich selbst aufrufende Funktionen/Methoden zu entwickeln.


Wir fangen an
...und zwar ganz einfach mit Angabe des Einstiegsverzeichnis $sRootDir und dem Initiieren der beiden SPL-Iteratoren RecursiveDirectoryIterator und RecursiveIteratorIterator. Für unser Beispiel gehen wir mal vom Einstiegsverzeichnis images aus:

PHP-Code:
$sRootDir 'images';

$itrDirectory = new RecursiveDirectoryIterator$sRootDir );
$itrIterator = new RecursiveIteratorIterator$itrDirectoryRecursiveIteratorIterator::SELF_FIRST ); 
Was wir jetzt haben ist ein Iterator, der es uns ermöglicht, uns im Dateisystem ab dem Einstiegspunkt zu bewegen und Informationen zu sammeln.
Zu Beachten ist, daß das Objekt an sich noch keine Daten enthält, sondern lediglich die Iteration und das Abrufen der Informationen über Methoden zur Verfügung stellt.

Die Iteration selbst kann praktischerweise wie bei Arrays mit foreach durchgeführt werden. Ich entscheide mich hier für die while-Variante, da ich dieser eine sinnigere Logik abgewinnen kann. Das ist allerdings nur meine persönliche Ansicht!


Sammeln der Informationen über die Iteration
Zunächst bereiten wir die Iteration vor, indem wir den Zeiger des Objektes mit der Methode rewind() zurücksetzen. Zudem deklarieren wir uns ein Array, das die gesammelten Daten am Ende enthält:
PHP-Code:
$aRecursiveDirContent = array();
$itrIterator->rewind(); 
Die Iteration an sich ist über while relativ einfach. Dazu bedienen wir uns der Methode valid(), die uns Auskunft darüber gibt, ob wir über ein gültiges Element verfügen:
PHP-Code:
while ( $itrIterator->valid() ) {

 
   // ... Informationen sammeln ( wird im nächsten Abschnitt detailliert beschrieben )

 
   $itrIterator->next();


Das ist bereits das Geheimnis der ganzen Iteration. Mit der Methode next() setzen wir den Zeiger des Objektes auf das nachfolgende Element.
Jetzt müssen wir nur noch...


Informationen sammeln
Jetzt kommt es auf den subjektiven Fall an, wie wir die Daten sammeln und welche überhaupt.
Ich habe für dieses kleine Tutorial mal für mich festgelegt, daß wir am Ende in $aRecursiveDirContent über alle Verzeichnisse als Schlüssel-Element verfügen, deren Werte auf Array-Basis die Dateien mit erweiterten Informationen enthalten.

Folgende Datei-Informationen wollen wir erhalten:
  • filename ( Dateiname )
  • filesize ( Dateigröße in Bytes )
  • permissions ( Dateiberechtigung Oktal )
  • created ( Erstellungsdatum, anhand der inode change Information )
  • modified ( letztes Änderungsdatum )
  • lastaccess ( letzter Dateizugriff )

Dazu holen wir uns zunächst über current() ein Objekt vom Typ SplFileInfo vom aktuellen Element und den Verzeichnisnamen mit der Methode getPath():
PHP-Code:
$splFileInfo $itrIterator->current();
$directory $splFileInfo->getPath(); 
Anhand dieser Daten entscheiden wir als erstes, ob es sich um ein neues Verzeichnis handelt, das noch nicht von uns "gesammelt" wurde und schreiben es bei Bedarf in unseren Container rein:
PHP-Code:
if ( $splFileInfo->isDir() && !isset($aRecursiveDirContent[$directory]) ) {

 
   $aRecursiveDirContent[$directory] = array();


Über die Methode isDir() prüfen wir, ob es sch bei dem aktuellen Element um ein Verzeichnis handelt.

Auf die gleiche Art prüfen wir mit der Methode isFile() im nächsten Step, ob es sich um eine Datei handelt und tragen unsere Informationen zusammen. Dazu möchte ich erstmal den gesamten Code-Block zeigen und die wichtigen Punkte hinterher ansprechen:
PHP-Code:
if ( $splFileInfo->isFile() ) {

 
   $aRecursiveDirContent[$directory][] = array(
 
           'filename' => $splFileInfo->getFileName(),
 
           'filesize' => $splFileInfo->getSize(),
 
           'permissions' => substrsprintf('%o'$splFileInfo->getPerms()), -),
 
           'created' => date'd.m.Y H:i:s'$splFileInfo->getCTime() ),
 
           'modified' => date'd.m.Y H:i:s'$splFileInfo->getMTime() ),
 
           'lastaccess' => date'd.m.Y H:i:s'$splFileInfo->getATime() )
 
       );


Im Prinzip ist das schon alles. Wie erkennbar ist, sammeln wir einfach alle Informationen über entsprechende Methoden in unserem Container-Array $aRecursiveDirContent.

Der Vollständigkeit, hier nochmal die verwendeten Methoden der Datei-Informationen:
  • getFilename()
    Gibt den Dateinamen zurück
  • getSize()
    Gibt die Dateigröße in Bytes an
  • getPerms()
    Liefert die Dateirechte als Integer. Über sprintf wandeln wir die Ausgabe oktal um und holen uns über substr nur die relevanten letzten vier Stellen.
  • getCTime()
    Liefert das Erstellungsdatum als Timestamp ( ermittelt anhand der change inode time )
  • getMTime()
    Liefert das Datum der letzten Aktualisierung als Timestamp.
  • getATime()
    Liefert das Datum des letzten Dateizugriffs als Timestamp.

Damit haben wir nun alle Daten in einem Array gesammelt, dies könnt ihr euch testweise mit print_r oder var_dump ausgeben lassen. Die Ausgabe kann bspw. so aussehen:
Code:
Array
(
   [/images] => Array
       (
           [0] => Array
               (
                   [filename] => logo.png
                   [filesize] => 14707
                   [permissions] => 0644
                   [created] => 30.03.2015 21:35:43
                   [modified] => 30.03.2015 21:36:32
                   [lastaccess] => 30.03.2015 21:36:32
               )

           [1] => Array
               (
                   [filename] => error.png
                   [filesize] => 623
                   [permissions] => 0644
                   [created] => 17.03.2015 17:41:18
                   [modified] => 15.02.2015 22:36:12
                   [lastaccess] => 15.02.2015 22:36:12
               )

           [2] => Array
               (
                   [filename] => close.png
                   [filesize] => 950
                   [permissions] => 0644
                   [created] => 17.03.2015 17:41:13
                   [modified] => 15.02.2015 22:36:10
                   [lastaccess] => 15.02.2015 22:36:10
               )

           [...]


Der komplette Code zur Übersicht
Um das kleine Tutorial damit abzuschliessen, hier nochmal der ganze Code als Übersicht:
PHP-Code:
$sRootDir 'images';

$itrDirectory = new RecursiveDirectoryIterator$sRootDir );
$itrIterator = new RecursiveIteratorIterator$itrDirectory );


$aRecursiveDirContent = array();
$itrIterator->rewind();


while ( 
$itrIterator->valid() ) {

 
   $splFileInfo $itrIterator->current();
 
   $directory $splFileInfo->getPath();

 
   if $splFileInfo->isDir() && !isset($aRecursiveDirContent[$directory]) ) {

 
      $aRecursiveDirContent[$directory] = array();

 
   }

 
   if $splFileInfo->isFile() ) {

 
       $aRecursiveDirContent[$directory][] = array(
 
               'filename' => $splFileInfo->getFileName(),
 
               'filesize' => $splFileInfo->getSize(),
 
               'permissions' => substrsprintf('%o'$splFileInfo->getPerms()), -),
 
               'created' => date'd.m.Y H:i:s'$splFileInfo->getCTime() ),
 
               'modified' => date'd.m.Y H:i:s'$splFileInfo->getMTime() ),
 
               'lastaccess' => date'd.m.Y H:i:s'$splFileInfo->getATime() )
 
           );

 
   }

 
   $itrIterator->next();


Drucke diesen Beitrag

  HTML Mail versenden mit PHPMailer
Geschrieben von: Arne Drews - 29.04.2015, 00:26 - Forum: Tutorials - Keine Antworten

HTML E-Mail mit dem PHPMailer versenden
Eine Mail mit PHP-Boardmitteln zu versenden kann schnell echte Probleme bereiten. Das liegt nicht zwingend an der mail()-Funktion selbst, die PHP bietet, sondern eher daran, daß man selber verantwortlich für die korrekte Formatierung nach RFC-Standards ist. RFC's ( Request For Comments ) beschreiben den Aufbau einer Mail und die Verbindung zum Mail-Server. Um eine Mail selbst zu versenden benötigen wir Kenntnisse über folgende RFC's:

Wie jeder sehen kann, ist das eine Menge Stoff, nur um eine Mail zu senden.
Aber halten wir uns nicht daran oder richten uns zumindest danach, geht der Mail-Versand ganz schnell schief. Im schlimmstem Fall werden wir sogar als SPAM gewertet und landen auf einer Blacklist.

Damit das nicht passiert und wir problemlos RFC-konforme Mails senden können, gibt es Mailerklassen, die uns die ganze Arbeit abnehmen.
Eine von den bekannteren ist der PHPMailer, mit dem wir uns hier kurz befassen wollen.
Hinweis
Natürlich gibt es nicht nur den PHPMailer. Wer bspw. lieber den SwiftMailer einsetzen möchte, sollte sich das äquivalente Tutorial zu dieser Mailer-Klasse ansehen: HTML E-Mails versenden mit dem SwiftMailer

Wie implementiere ich PHPMailer?
Tipp
Der folgende Abschnitt erklärt das Einbinden des PHPMailer Version 5. Es ist zu empfehlen, aktuell die Version 6 zu verwenden. Download: https://github.com/PHPMailer/PHPMailer/archive/master.zip
Wie das Einbinden mit der Version 6 auf ähnlich einfache Weise funktioniert, habe ich hier beschrieben: PHPMailer Version 6 erfolgreich einbinden
Nachdem ihr wie dort beschrieben die Version 6 erfolgreich eingebunden habt, ist die grundlegende Handhabung wieder gleich, so dass ihr beim nächsten Abschnitt ( "Wie verwende ich das jetzt?" ) fortfahren könnt
Aus dem Package, das wir hier ( Achtung: Version 6! siehe Tipp oben ) runterladen können, benötigen wir zum Versand nur die class.phpmailer.php und class.smtp.php, da wir unsere Mails direkt über SMTP versenden wollen. Das Package enthält zusätzlich eine Datei PHPMailerAutoload.php, die dafür sorgt, daß die von uns genutzte Klassen automatisch geladen werden.
Diese drei Dateien legen wir auf unserem Webspace in einem beliebigen Verzeichnis ab. Für unser Beispiel nennen wir das Verzeichnis phpmailer/.
Das war alles, was an Vorbereitung notwendig ist.

Wie verwende ich das jetzt?
Die Verwendung ist im Prinzip ganz einfach. Zunächst müssen wir den Autoloader einbinden und direkt eine Instanz des PHPMailer erstellen:
PHP-Code:
include_once 'phpmailer/PHPMailerAutoload.php'// Hinweis für die Version 6, einen Abschnitt zuvor beachten !!!
$oMailer = new PHPMailer;
$oMailer->CharSet 'UTF-8'
Hinweis
Um keine CharsetEncoding-Fehler zu bekommen, teilen wir dem PHPMailer-Objekt direkt nach der Instanziierung über die Eigenschaft CharSet mit, dass wir UTF-8 verwenden.
Dies muss zwingend direkt nach der Instanziierung stattfinden, da ansonsten bereits Mail-Header geschrieben sein könnten.
Und schon sind wir vorbereitet und können loslegen. Als erstes sollten wir die für das SMTP-Protokoll erforderlichen Parameter setzen:
PHP-Code:
// SMTP aktivieren
$oMailer->isSMTP();

// SMTP-Server
$oMailer->Host 'smtp.example.com';

// SMTP Authentifizierung aktivieren
$oMailer->SMTPAuth true;

// SMTP Benutzer
$oMailer->Username 'phprocks@example.com';

// SMTP Benutzer Passwort
$oMailer->Password 'foobar';

// Verbindungssicherheit setzen ( SSL und TLS möglich )
$oMailer->SMTPSecure 'tls';

// Verbindungsport festlegen
$oMailer->Port 587
Den SMTP-Benutzer benötigen wir, um uns am Mailserver zu authentifizieren, sofern erforderlich. Diese Daten sollten wir kennen oder über unseren Provider in Erfahrung bringen.
Damit ist unsere Verbindung festgelegt und wir kümmern uns um die wichtigsten Header-Daten. Hier legen wir den/die Empfänger und Absender-Daten fest.
PHP-Code:
// Absender Adresse setzen
$oMailer->From 'phprocks@example.com';

// Absender Alias setzen
$oMailer->FromName 'PHProcks!';

// Empfänger Adresse und Alias hinzufügen
$oMailer->addAddress'max.mustermann@example.com''Max Mustermann' ); 
Die wichtigsten Einstellungen sind nun vorgenommen, es fehlen nur noch der Betreff und der Nachrichteninhalt. Da wir eine HTML-Mail versenden wollen, müssen wir dies unserem Objekt "mitteilen":
PHP-Code:
// HTML aktivieren
$oMailer->isHTMLtrue );

// Betreff
$oMailer->Subject 'PHProcks! Tutorials - less time to learn more';

// Der Nachrichteninhalt als HTML
$oMailer->Body '<h1>PHProcks!</h1><h2>Tutorial: HTML E-Mail senden mit PHPMailer</h2>';

// Alternaiver Nachrichteninhalt für Clients, die kein HTML darstellen
$oMailer->AltBody strip_tags$oMailer->Body ); 

Hinweis
Für die Clients, die kein HTML darstellen, nutzen wir hier der Einfachheit halber die Funktion strip_tags(). Im produktiven Fall sollte hier allerdings die alternative Nachricht für reine Text-Mails hinterlegt werden.

Wir haben unsere Mail mit Hilfe des PHPMailer nun aufgebaut und können diese versenden. Der PHPMailer kümmert sich dabei um den korrekten Aufbau nach RFC.
Sinnvollerweise möchten wir gerne erfahren, ob die Übergabe an den SMTP-Server funktioniert hat. Dazu prüfen wir den Rückgabewert der send()-Methode:
PHP-Code:
if ( !$oMailer->send() ) {

 
   echo 'Something\'s went wrong!';
 
   exit;

}

echo 
'Yes! First Mail with PHPMailer sent successfully!'

Zusammenfassung
Wie wir gesehen haben, ist es gar nicht so kompliziert, eine HTML-Mail sauber zu versenden, auch ohne großartig professionelle Kenntnisse zu besitzen.
Um den Kern unseres Beispiels im Überblick zusammenzufassen, hier nochmal der gesamte Beispielcode ohne Kommentare und unnötige Formatierungen:
PHP-Code:
include_once 'phpmailer/PHPMailerAutoload.php';
$oMailer = new PHPMailer;
$oMailer->CharSet 'UTF-8';

$oMailer->isSMTP();
$oMailer->Host 'smtp.example.com';
$oMailer->SMTPAuth true;
$oMailer->Username 'phprocks@example.com';
$oMailer->Password 'foobar';
$oMailer->SMTPSecure 'tls';
$oMailer->Port 587;

$oMailer->From 'phprocks@example.com';
$oMailer->FromName 'PHProcks!';
$oMailer->addAddress'max.mustermann@example.com''Max Mustermann' );

$oMailer->isHTMLtrue );
$oMailer->Subject 'PHProcks! Tutorials - less time to learn more';
$oMailer->Body '<h1>PHProcks!</h1><h2>Tutorial: HTML E-Mail senden mit PHPMailer</h2>';
$oMailer->AltBody strip_tags$oMailer->Body );


if ( !
$oMailer->send() ) {

 
   echo 'Something\'s went wrong!';
 
   exit;

}

echo 
'Yes! First Mail with PHPMailer sent successfully!'
Hinweis
In diesem Tutorial verwenden wir das SMTP-Protokoll, um die E-Mails mit dem PHPMailer zu versenden. Voraussetzung dafür ist immer ein gültiger und korrekt konfigurierter SMTP-Account bei einem entsprechenden Anbieter. Wer dies nicht hat, oder es zu Problemen kommt, wenn ihr E-Mails darüber versendet, kann den PHPMailer auch ohne SMTP verwenden. Dazu müssen einfach diese SMTP-Methoden und Eigenschaften weggelassen werden:
PHP-Code:
$oMailer->isSMTP();
$oMailer->Host 'smtp.example.com';
$oMailer->SMTPAuth true;
$oMailer->Username 'phprocks@example.com';
$oMailer->Password 'foobar';
$oMailer->SMTPSecure 'tls';
$oMailer->Port 587
Der PHPMailer nutzt dann als Fallback die PHP interne mail() Funktion. Dadurch, dass der PHPMailer die Daten bzw. die Mail weitesgehend RFC konform vorbereitet, ist dies für Einsteiger immer noch die deutlich bessere Variante, als mail() ohne Kenntnisse roh zu verwenden!
Hinweis
Alternativ zum PHPMailer gibt es noch SwiftMailer. Der SwiftMailer ist zwar etwas komplexer wie PHPMailer, aber ebenso einfach verwendbar und meine persönliche Empfehlung.
Ein kurzes Tutorial darüber findet ihr hier: HTML E-Mails versenden mit dem SwiftMailer

Drucke diesen Beitrag

  Ein kurzer Einstieg in PDO und Prepared Statements
Geschrieben von: Arne Drews - 27.04.2015, 23:39 - Forum: Tutorials - Keine Antworten

Was ist PDO?
PDO steht für PHP Data Objects und stellt eine Schnittstelle bereit, um mit PHP auf Datenbanken zugreifen zu können.
Verwendet wird dafür ein spezifischer Datenbanktreiber, über den die Verbindung zum Datenbankserver hergestellt wird.
Durch die PDO-Abstraktionsschicht kann dann, ganz gleich welche Datenbank verwendet wird, mit ein und denselben Methoden Abfrage erstellen, Daten lesen/schreiben etc.
PDO bietet die Möglichkeit, Prepared Statements zu verwenden, um die Gefahr von SQL-Injection zu verringern.

Wie sieht das in der Praxis aus?
PDO bietet zwei wichtige Objekte. Als erstes natürlich das PDO-Objekt selbst, das grob gesagt die Verbindung zur Datenbank repräsentiert.
Und als zweites das PDOStatement-Objekt, das die Verwendung von Prepared-Statements erlaubt.

Zunächst benötigen wir eine Instanz der Klasse PDO, die wir mit einem einfachen Aufruf des Konstruktors erhalten:

PHP-Code:
$pdoObject = new PDO$sDsn$sUsername$sPassword$aOptions ); 
Im Prinzip ist das schon alles, was wir benötigen, um eine Verbindung mit einem Datenbank-Server aufnehmen zu können. Was aber sollen die Parameter nun bedeuten?

Schauen wir uns die Parameter zum Verständnis mal genauer an:
  • $sDsn
    Der sogenannte Data Name Source enthält eine Zeichenkette mit allen notwendigen Parametern, die wir zum Verbindungsaufbau benötigen, wie z.B. den PDO-Treiber, den Datenbank-Server, u.a.
  • $sUsername
    Der Benutzername für die Anmeldung am Datenbank-Server
  • $sPassword
    Passwort für die Anmeldung am Datenbank-Server
  • $aOptions
    Ein Array mit optionalen Attributen ( wird später noch drauf eingegangen )
Da $sUserame und $sPassword selbsterklärend sein sollten, spare ich mir die weitere Ausführung dazu und gehe nur auf $sDsn und $aOptions ein.

Data Name Source ( DSN ) - $sDsn
In der Data Name Source geben wir die notwendigen Parameter für den Verbindungsaufbau an. Als Beispiel soll folgende gültige DSN genügen:
PHP-Code:
$sDsn 'mysql:host=localhost;dbname=testdb;charset=utf8'
Die Angaben des DSN kurz erklärt:
  • mysql:
    Der PDO-Datenbanktreiber. In unserem Beispiel greifen wir auf eine MySQL-Datenbank zu.
    PDO bietet weitere Treiber für verschiedenste Datenbanken an. Weitere Informationen findet ihr hier: PDO-Treiber
  • host=
    Die Angabe des Datenbankservers, in unserem Beispiel ist dies der localhost.
  • dbname=
    Der Name der Datenbank, auf die wir zugreifen möchten, in unserem Fall testdb.
  • charset=
    Das CharsetEncoding für die Verbindung, in unserem Beispiel utf8 ( Unicode )
Weitere mögliche Parameter sind hier zu finden: PDO-MySQL DSN Elemente

Verbindungsoptionen - $aOptions
Über die Verbindungsoptionen können wir der Verbindung Parameter mitgeben, die das Verhalten beeinflussen.
Einige Verbindungsoptionen findet ihr u.a. hier: PDO - ATTR_*- Konstanten

Für unser Beispiel nutzen wir die folgenden drei Parameter:
PHP-Code:
$aOptions = array(
 
           PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
 
           PDO::ATTR_EMULATE_PREPARES => false,
 
           PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    
); 
Was bedeuten diese Angaben nun wieder?
  • PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ
    Gibt an, daß wir die Rückgabe eines Datensatzes von Mehoden, wie bspw. PDOStatement::fetch() als Objekt erhalten möchten. Per Standard werden diese als assoziatives Array zurückgegeben. Da wir aber OOP versiert sind, möchten wir natürlich unsere Datensätze auch als Objekte verarbeiten.
  • PDO::ATTR_EMULATE_PREPARES => false
    Der PDO-Treiber für MySQL emuliert per Standard die PreparedStatements nur, sendet dies aber nicht zur Datanbank. Mit dieser Einstellung sagen wir, daß wir nicht nur emulieren wollen, sondern PreparedStatements nutzen wollen.
  • PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    PDO liefert per Standard keine Fehler-Ausgaben ( PDO::ERRMODE_SILENT ). Wir veranlassen PDO mit dieser Option, Exceptions zu werfen, die wir dann abfangen und darauf reagieren können.
Das soll an dieser Stelle alles in Bezug auf die Verbindung sein.
Ich möchte im nächsten Step auf PreparedStatement mit PDOStatement eingehen.

PreparedStatements
Prepared Statements enthalten im Gegensatz zu einer Standard-Anweisung eine vorbereitete, die anstelle der Parameterwerte Platzhalter enthält. Mit diesem Prinzip ist es möglich, daß wir SQL-Injection effektiv verhindern.
PDO bietet wie bereits erwähnt das Objekt PDOStatement, welches PreparedStatements unterstützt. Ein Objekt der Klasse PDOStatement muß nicht explizit instanziiert werden, dies geschieht i.d.R. beim Aufruf von PDO::prepare(), das eine Query für die Ausführung vorbereitet und ein Objekt vom Typ PDOStatement zurückgibt.

Die Verwendung ist genau so einfach, wie bisher:
PHP-Code:
$pdoStmnt $pdoObject->prepare"SELECT email FROM mytable" ); 
Jetzt haben wir mit $pdoStmnt ein Objekt vom Typ PDOStatement. Aber wo liegt darin jetzt der Vorteil? Zumal die Abfrage bisher noch nicht einmal an die Datenbank gesendet wurde.
Nun, ein Vorteil liegt darin, daß wir an das Statement Parameter binden können, für die wir zuvor einen Marker oder Platzhalter gesetzt haben. Marker und Platzhalter können entweder als Fragezeichen ( ? ) oder als benannter Platzhalter ( :platzhalter ) gesetzt werden. Das Binden der Parameter-Werte ist über die Methoden PDOStatement::bindParam() und PDOStatement::bindValue() möglich.

Beispiel:
PHP-Code:
$sUserLastName 'Mustermann';

// mit Fragezeichen:
$pdoStmnt $pdoObject->prepare"SELECT email FROM mytable WHERE lastname=?" );
$pdoStmnt->bindParam1$sUserLastNamePDO::PARAM_STR );

// mit benannten Platzhaltern:
$pdoStmnt $pdoObject->prepare"SELECT email FROM mytable WHERE lastname=:userlastname" );
$pdoStmnt->bindParam':userlastname'$sUserLastNamePDO::PARAM_STR ); 

Hinweis
Bei Verwendung von Fragezeichen als Platzhalter gibt der erste Parameter von PDOStatement::bindParam() und PDOStatement::bindValue() den Offset, also die Position des zu ersetzenden Parameters in der Query an. Dabei beginnt die Nummerierung bei 1 und nicht, wie bspw. von Arrays gewohnt bei 0. Mit Verwendung der benannten Parameter sind wir unabhängig von der Offset-Angabe und zudem in der Lage in größeren Queries vorkommende Platzhalter-Duplikate mit nur einer Zuweisung über PDOStatement::bindParam() oder PDOStatement::bindValue() zu ersetzen.
PHP-Code:
$pdoStmnt $pdoObject->prepare"SELECT email FROM mytable WHERE firstname=:username OR lastname = :username" );
$pdoStmnt->bindParam':username'$sUsernamePDO::PARAM_STR ); 

Wir können als dritten Parameter der Methode PDO::bindParam() und PDO::bindValue() den Datentyp des gebundenen Wertes angeben. Die gebräuchlichsten Konstanten sind in diesem Fall PARAM_INT und PARAM_STR, welches gleichzeitig der Default ist, sofern wir nichts angeben. Weitere Konstanten und Beschreibungen findet ihr hier: PDO - Vordefinierte Konstanten

Jetzt haben wir zwar etwas über das Objekt PDOStatement und dessen Vorteile gelernt, aber wie bekomme ich nun das Ergebnis meiner Query zur weiteren Verarbietung?
Nun, dazu müssen wir die Query zunächst mal an die DB senden. Das machen wir mit der Methode PDOStatement::execute():
PHP-Code:
$pdoStmnt->execute(); 
Das Objekt $pdoStmnt enthält nun nach erfolgreicher Ausführung das Ergebnis der Abfrage. Aber wie kommen wir da jetzt ran?
Hierfür stehen uns die Methoden PDOStatement::fetch() und PDOStatement::fetchAll() zur Verfügung.

Hinweis
PDOStatement::fetch() und PDOStatement::fetchAll() geben immer ein assoziatives Array zurück, es sei denn wir geben der gewünschten Datentypen als dritten Parameter an oder ändern diesen explizit über die Optionen des Verbindungsaufbaus bzw. mit der Methode PDO:: setAttribute() unmittelbar nach dem Verbindungsaufbau. Das Attribute heißt ATTR_DEFAULT_FETCH_MODE und die akzeptierten Werte können hier nachgelesen werden: PDOStatement::fetch(). Da wir durchgehend mit Objekten arbeiten wollen, haben wir uns für den Wert PDO::FETCH_OBJ entschieden.

Erwartet man mehrere Datensätze und möchte diese gesammelt zurück bekommen, hilft die Methode PDOStatement::fetchAll(), die im Grunde genau wie PDOStatement::fetch() arbeitet, mit dem Unterschied, daß alle vorhandenen Datensätze zurück gegeben werden.

Hinweis
In der gängigen Praxis kommt es eher seltener vor, daß alle Datensätze zunächst gefetcht und dann verarbeitet werden. In den meisten Fällen wird über einen while-Kontext jede Datenzeile des Ergebnisses direkt verarbeitet:
PHP-Code:
while ( $dsRow $pdoStmnt->fetch() ) {

 
   echo $dsRow->email '<br />';



Das komplette Code-Beispiel
PHP-Code:
// vorbereitende Variablen für den Verbindungsaufbau
$sDsn 'mysql:host=localhost;dbname=testdb;charset=utf8';
$sUsername 'testuser';
$sPassword 'testpassword';

// zusätzliche Optionen
$aOptions = array(
 
           PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
 
           PDO::ATTR_EMULATE_PREPARES => false,
 
           PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    
);

// Suchkriterium für unsere Abfrage
$sUserLastName 'Mustermann';

// Instanziierung
$pdoObject = new PDO$sDsn$sUsername$sPassword$aOptions );

// Prepared Statement instanziieren
$pdoStmnt $pdoObject->prepare"SELECT email FROM mytable WHERE lastname=:userlastname" );
$pdoStmnt->bindParam':userlastname'$sUserLastNamePDO::PARAM_STR );

// Abfrage ausführen
$pdoStmnt->execute();

// Rückgabe verarbeiten
while ( $dsRow $pdoStmnt->fetch() ) {

 
   echo $dsRow->email '<br />';


Drucke diesen Beitrag

  JOIN sinnvoll zusammenfassen ?
Geschrieben von: Arne Drews - 08.04.2015, 11:36 - Forum: Andere SQL Datenbanken - Antworten (2)

Hallo,

Ich erstelle gerade einen Artikel-Export, der auf multiple Textresourcen zurückgreift.
Diese binde ich derzeit einzeln mit JOIN ein, könnte mir aber vorstellen, daß das cleverer gelöst werden könnte?!

Vorraussetzungen
Ich arbeite auf einem MSSQL-Server, aber ich denke die Frage ist durchaus allgemein stellbar.
Als Grundlage dienen zwei Tabellen:

  • ShopItems
  • ShopTextResourcesLanguages
In der ShopItems befinden sich u.a. die Integer-Spalten Bullet1 bis Bullet5.
In der ShopTextResourcesLanguages befinden sich zu der ItemId die entsprechenden Texte pro LanguageId.

Aktueller Vorgang
Zur Zeit ziehe ich mir die Texte, in dem ich die ShopTextResourcesLanguages 5x JOINe, pro Bullet 1x.
Code:
SELECT
   ShopItems.ItemId,
   Bullet1.[Description] as Bullet1,
   Bullet2.[Description] as Bullet2,
   Bullet3.[Description] as Bullet3,
   Bullet4.[Description] as Bullet4,
   Bullet5.[Description] as Bullet5

FROM
   ShopItems
JOIN
   ShopTextResourcesLanguages Bullet1 ON ShopItems.Bullet1 = Bullet1.TextId
JOIN
   ShopTextResourcesLanguages Bullet2 ON ShopItems.Bullet2 = Bullet2.TextId
JOIN
   ShopTextResourcesLanguages Bullet3 ON ShopItems.Bullet3 = Bullet3.TextId
JOIN
   ShopTextResourcesLanguages Bullet4 ON ShopItems.Bullet4 = Bullet4.TextId
JOIN
   ShopTextResourcesLanguages Bullet5 ON ShopItems.Bullet5 = Bullet5.TextId

Natürlich gehe ich u.a. noch auf die LanguageId ein, aber das sollte für die Frage irrelevant sein.

Meine Frage ist nun:
Macht das Sinn oder gibt es eine bessere Lösung, die Text-Ressourcen einzuhängen?
Eine Anpassung der DB-Struktur ist keine Lösung, weil es sich dabei um unser WaWi-System handelt.


Würde mich über Anregungen bzw. Tipps freuen
Danke

Drucke diesen Beitrag

  Frohe Ostern
Geschrieben von: Arne Drews - 04.04.2015, 15:02 - Forum: Off Topic - Antworten (2)

[Bild: http://www.php-rocks.de/images/phprocks-ostern.jpg]

Drucke diesen Beitrag

  Das habe ich auch noch nicht gesehen :)
Geschrieben von: Arne Drews - 03.04.2015, 14:23 - Forum: Off Topic - Antworten (2)

[Bild: http://www.php-rocks.de/images/phprocks-google.jpg]

Der Googlebot schleicht also als Benutzer hier durch:
https://www.google.de/?gws_rd=ssl#q=site:php-rocks.de

Drucke diesen Beitrag

  Hervorhebung ungelesene Threads
Geschrieben von: Arne Drews - 26.03.2015, 22:57 - Forum: Off Topic - Antworten (4)

Ich finde die Hervorhebung der ungelesenen Threads in der Übersicht nur durch den grünen Kuller nicht so sehr gelungen.
Meine Idee war, das über die Background-Colour hervorzuheben ( siehe Anhang ).
Vielleicht gibts da ja noch interessante Sichtweisen zu?



Angehängte Dateien Thumbnail(s)
   
Drucke diesen Beitrag

  Beitrags-Editor: Quellcode- / WYSIWYG-Ansicht deutlicher hervorheben
Geschrieben von: Arne Drews - 26.03.2015, 20:57 - Forum: Off Topic - Antworten (7)

Hallo,

Als Anreiz aus diesem Post, möchte ich mal gerne eure Meinung zu dem Thema der Ansicht des Beitrag-Editors erfahren.

Meine Idee geht dahin, daß ich den Button für die WYSIWYG-Ansicht farblich hervorhebe, als bspw. die angedeuteten Textzeilen farblich, damit erkennbar ist, in welchem Modus man sich befindet.

Eine weitere Möglichkeit wäre, das über einen Border oder eine Background-Color zu unterscheiden.

Die Umfrage wird drei Tage laufen.
Bin gespannt, wie sich die Meinungen verteilen.

Danke und Gruß
Arne

Drucke diesen Beitrag

  PDOStatement::execute() mit Array-Übergabe
Geschrieben von: Arne Drews - 26.03.2015, 13:01 - Forum: PHP Basics - Antworten (4)

So, nun würde mich mal was interessieren.

Ich nutze das Parameter-Binding für Prepared Statements i.d.R. immer mit bindParam():

PHP-Code:
$pdoStatement $pdoInstance->prepare"SELECT `column` FROM `table` WHERE `sometext`=? and `id`=?" );
$pdoStatement->bindParam1$sometextPDO::PARAM_STR );
$dpoStatement->bindParam2$myIdPDO::PARAM_INT );

$pdoStatement->execute();
// usw... 

Für mein Verständnis reagiert PDOStatement jetzt auf die übergebenen Datentypen, denn würde er bspw. auch $myId als String übergeben bekommen, müsste er den gefilterten Wert ja z.B. noch in Quotes setzen, was aber für MySQL nicht korrekt wäre. Abgesehen davon, daß die Filterung ja auch Datentyp bedingt sein sollte.

Nun gibt es die execute()-Methode, mit der man die Values auch per Array übergeben kann. Die aber übergibt ja erstmal alle Values zunächst als PARAM_STR, also auch die ID als String.
Jetzt frage ich mich, wie zuverlässig das dann ist? Erkennt er trotzdem, daß es sich bei $myId um einen Ganzzahlenwert handelt und behandelt den dann intern doch wieder als Integer?
Wenn ja, woher will er wissen, daß nicht auch ein Integer-Wert in eine VARCHAR-Spalte geschriebenen werden könnte/sollte?!

Vielleicht kann mir dazu jemand mal den Horizont erweitern?
Danke!

Drucke diesen Beitrag