Google ReCaptcha ins Phalcon PHP-Framework implementieren

In diesem Artikel möchte ich euch zeigen, wie ihr die neueste Version von Googles ReCaptcha-Dienst genauso einfach wie sauber in ein mit Phalcon geschriebenes Projekt implementiert.

Hinweis

Der Einfachheit halber arbeite ich mit einer Projekt-Vorlage, die mit Hilfe der Phalcon Developer Tools erzeugt wurde. Je nachdem, ob ihr ein bereits bestehendes Projekt editiert und wie dieses aufgebaut ist, kann es sein, dass dieses von der Vorlage abweicht. In diesem Fall müsst ihr möglicherweise andere Dateien editieren, als in diesem Artikel angegeben. Eine Adaption für bestehende Projekte sollte jedoch kein Problem sein, da ihr ja bereits Erfahrungen mit Phalcon gesammelt habt.

Vorbereitung

Ich gehe zunächst einmal davon aus, dass ihr euch mit den folgenden Programmen auskennt und diese auch installiert habt:

Außerdem benötigt ihr ein Google-Konto, mit dem ihr euch auf der ReCaptcha-Webseite anmeldet. Dort müsst ihr für jedes Projekt bzw. für jede Domain einen neuen Satz Schlüssel, bestehend aus Webseite-Schlüssel (öffentlich) und geheimen Schlüssel (privat), generieren. Diese werden wird im späteren Verlauf des Artikels verwenden, um mit den Google-Servern zu kommunizieren. Tipp: Es ist auch möglich einen einzigen Schlüsselsatz auf mehreren Domains/Projekten zu verwenden, allerdings wird dies explizit nicht empfohlen.

Neues Projekt anlegen

Öffnet ein Terminal-Fenster bzw. die Kommandozeile/Eingabeaufforderung und verwendet den folgenden Befehl um mittels der Phalcon Developer Tools ein neues Projekt zu erzeugen.

> phalcon project recaptcha

Möchtet ihr die Developer Tools von Phalcon nicht verwenden, müsst ihr ein neues Projekt manuell anlegen. Mein Tipp: Spart euch die Arbeit, es ist wirklich mühselig.

Google ReCaptcha via Composer einbinden

Öffnet nun einen Editor eurer Wahl und erstellt unterhalb des Projekt-Ordners recaptcha/ eine neue Datei namens composer.json. Fügt den folgenden JSON-Code in die Datei ein und speichert sie ab. Die Verwendung von Composer ist übrigens optional.

{
"config": {
"vendor-dir": "app/vendor"
},
"require": {
"google/recaptcha": "~1.1"
}
}

Im Anschluss führt ihr den folgenden Befehl im Projekt-Ordner aus und lasst Composer seine Arbeit machen. Dabei werden automatisch alle Abhängigkeiten in den Unterordner app/vendor/ installiert eine Datei namens autoload.php angelegt.

> composer install

Alternativ zur Verwendung von Composer könnt ihr die PHP-Quelltexte für ReCaptcha auch über Googles Git-Repository herunterladen und manuell installieren sowie den Autloader von Phalcon anweisen die Klassen automatisch zu laden.

Phalcon-Konfigurationsdatei anpassen

Um die im nächsten Schritt benötigten Verzeichnisse zu verwenden, muss die Datei app/config/config.php angepasst und die Pfade hinterlegt werden (Zeilen 18-20). Auch tragen wir hier das Schlüsselpaar für unser Projekt ein (Zeilen 23-27). Dieses findet ihr nach Erstellung auf der ReCaptcha-Webseite.

<?php
// Konfigurations-Klasse
return new \Phalcon\Config(array(
'database' => array(
'adapter' => 'Mysql',
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
),
'application' => array(
'controllersDir' => __DIR__ . '/../../app/controllers/',
'modelsDir' => __DIR__ . '/../../app/models/',
'viewsDir' => __DIR__ . '/../../app/views/',
'pluginsDir' => __DIR__ . '/../../app/plugins/',
'libraryDir' => __DIR__ . '/../../app/library/',
'cacheDir' => __DIR__ . '/../../app/cache/',
'elementsDir' => __DIR__ . '/../../app/elements/',
'formsDir' => __DIR__ . '/../../app/forms/',
'validatorsDir' => __DIR__ . '/../../app/validators/',
'baseUri' => '/',
),
'ReCaptcha' => array(
'siteKey' => '6LfqOAoTAAAAAL1n86fhSqUjzsXZI_oGZ1kAKfPk',
'secret' => '6LfqOAoTAAAAAKEbnwWpYShZOnbvJVh_OHssYCoc',
'language' => 'de'
)
));

Phalcon-Autoloader anpassen und Composer-Autoloader integrieren

Nun öffnen wir die Datei app/config/loader.php und fügen drei neue Verzeichnisse zum Autoloader hinzu. Diese beinhalten später die benötigten Dateien für ReCapcha-Element, -Formular sowie den Validator (Zeilen 10-12). Außerdem wird der Autoloader von Composer beim Laden von Namespaces und Klassen innerhalb von Phalcon nicht berücksichtigt. Daher bedarf es an dieser Stelle einer kleinen Änderung, damit die von Composer installierten Abhängigkeiten auch im Projekt zur Verfügung stehen (Zeilen 16-17).

<?php
// Autoloader instanzieren
$loader = new Phalcon\Loader();
// Autoloader für Verzeichnisse aktivieren
$loader->registerDirs(
array(
$config->application->controllersDir,
$config->application->modelsDir,
$config->application->elementsDir,
$config->application->formsDir,
$config->application->validatorsDir
)
)->register();
// Composer-Autoloader implementieren
require '../app/vendor/autoload.php';

Zusätzliche Dienste in Phalcon laden

Im nächsten Schritt bedarf es noch einer Änderung an den Diensten, die ihr über den Dependency Injector von Phalcon global zur Verfügung stellt. Fügt dazu das use-Statement (Zeile 9), sowie die Konfigurations-Klasse (Zeilen 71-76) und die Flash-Komponente zum Anzeigen von Statusmeldungen (Zeilen 78-83) in die Datei app/config/services.php ein.

<?php
use Phalcon\DI\FactoryDefault,
Phalcon\Mvc\View,
Phalcon\Mvc\Url as UrlResolver,
Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter,
Phalcon\Mvc\View\Engine\Volt as VoltEngine,
Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter,
Phalcon\Session\Adapter\Files as SessionAdapter,
Phalcon\Flash\Session as FlashSession;
// Dependency Injector instanzieren
$di = new FactoryDefault();
// URL-Komponente laden
$di->set('url', function() use ($config)
{
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
}, TRUE);
// Volt-Template-Engine verwenden
$di->set('view', function() use ($config)
{
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(array(
'.volt' => function ($view, $di) use ($config)
{
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_'
));
return $volt;
},
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
));
return $view;
}, TRUE);
// Datenbank-Verbindung herstellen
$di->set('db', function() use ($config)
{
return new DbAdapter(array(
'host' => $config->database->host,
'username' => $config->database->username,
'password' => $config->database->password,
'dbname' => $config->database->dbname
));
});
// Sessions aktivieren
$di->set('session', function()
{
$session = new SessionAdapter();
$session->start();
return $session;
});
// Konfiguration bereitstellen
$di->set('config', function() use ($config)
{
return $config;
});
// Flash-Nachrichten implementieren
$di->set('flash', function()
{
return new FlashSession();
});

ReCaptcha-Element erzeugen

Als nächstes legen wir ein neues Element an, welches später im Formular für die Darstellung des ReCaptcha verwendet wird. Erstellt eine neue Datei namens app/elements/ReCaptchaElement.php und fügt den nachfolgenden Quelltext in die Datei ein.

<?php
use Phalcon\DI\FactoryDefault,
Phalcon\Forms\Element;
// ReCaptcha-Element
class ReCaptchaElement extends Element
{
public function render($attributes = NULL)
{
// Konfiguration beziehen
$config = FactoryDefault::getDefault()->getConfig();
// HTML-Code erzeugen
$html = '<div class="g-recaptcha" data-sitekey="%1$s"></div>';
$html .= '<script src="//www.google.com/recaptcha/api.js?hl=%2$s"></script>';
// Platzhalter füllen und HTML zurückgeben
return sprintf(
$html,
$config->ReCaptcha->siteKey,
$config->ReCaptcha->language
);
}
}

ReCaptcha-Validator anlegen

Um später überprüfen zu können, ob der Benutzer das ReCaptcha abgesendet und erfolgreich gelöst hat, benötigen wir einen eigenen Validator, den wir nun anlegen. Erstellt hierzu eine neue Datei mit dem Namen app/validators/ReCaptchaValidator.php und nutzt den folgenden Quelltext dafür.

<?php
use Phalcon\DI\FactoryDefault,
Phalcon\Validation,
Phalcon\Validation\Validator,
Phalcon\Validation\ValidatorInterface,
Phalcon\Validation\Message,
ReCaptcha\ReCaptcha;
// ReCaptcha-Validator
class ReCaptchaValidator extends Validator implements ValidatorInterface
{
public function validate(Validation $validator, $attributes)
{
// Konfiguration und Request-Objekt beziehen
$di = FactoryDefault::getDefault();
$config = $di->getConfig();
$request = $di->getRequest();
// Googles ReCaptcha-Klasse instanzieren
$recaptcha = new ReCaptcha($config->ReCaptcha->secret);
// Antwort von ReCaptcha-API beziehen
$response = $recaptcha->verify(
$request->getPost('g-recaptcha-response'),
$request->getClientAddress()
);
// Antwort überprüfen
if (!$response->isSuccess())
{
// Nachricht dem Validator hinzufügen
$validator->appendMessage(
new Message(
$this->getOption('message') ?: 'Bitte ReCaptcha ausfüllen',
$attributes,
'ReCaptcha'
)
);
// Prüfung fehlgeschlagen
return FALSE;
}
// Erfolgreich
return TRUE;
}
}

Beispiel-Formular erstellen

Nun erzeugen wir ein neues Formular, in dem wir das zuvor erstellte Element sowie den Validator verwenden um das ReCaptcha-Widget anzeigen und die Eingabe des Benutzers zu validieren. Verwendet hierfür die nachfolgende Vorlage und speichert sie unter app/forms/ReCaptchaForm.php ab.

<?php
use Phalcon\Forms\Form,
Phalcon\Forms\Element\Text,
Phalcon\Validation\Validator\PresenceOf;
// ReCaptcha-Formular
class ReCaptchaForm extends Form
{
public function initialize()
{
// Elemente instanzieren
$name = new Text('name');
$recaptcha = new ReCaptchaElement('recaptcha');
// Validator für Name-Feld
$name->addValidator(
new PresenceOf(array(
'message' => 'Bitte Namen eingeben'
))
);
// Validator für ReCaptcha
$recaptcha->addValidator(
new ReCaptchaValidator(array(
'message' => 'Bitte ReCaptcha ausfüllen'
))
);
// Elemente zum Formular hinzufügen
$this->add($name);
$this->add($recaptcha);
}
}

Controller anpassen

Im Controller erwarten euch gleich mehrere Aufgaben: Dort implementiert ihr die Logik zur Anzeige als auch zur Validierung des Formularss, sowie die Übergabe des abgesendeten Feldes (Zeilen 8-39). Dies geschieht in der Datei app/controllers/IndexController.php.

<?php
// Index-Controller
class IndexController extends ControllerBase
{
// Index-Action
public function indexAction()
{
// ReCaptcha-Formular instanzieren
$form = new ReCaptchaForm();
// Auf POST-Request prüfen
if ($this->request->isPost())
{
// Formular validieren
if (!$form->isValid($this->request->getPost()))
{
// Meldungen ausgeben
foreach ($form->getMessages() as $message)
{
$this->flash->error($message);
}
}
else
{
// POST-Variable übergeben und anderen View auswählen
$this->view->name = $this->request->getPost('name');
$this->view->pick('index/success');
}
}
// Formular an View übergeben
$this->view->form = $form;
}
}

View-Templates hinterlegen

Zu guter Letzt benötigen wir noch zwei Templates für die beiden Views: Eine für die Anzeige des Formulars und die andere zur Anzeige der Seite nach erfolgreichem Versand.

Die Datei app/views/index/index.volt dient zum Anzeigen des Formulars und der Status-Meldungen, falls die Validierung fehlschlägt.

<h1>Google ReCaptcha ins Phalcon PHP-Framework implementieren</h1>
{{ form(null, 'method': 'post') }}
<p>
{{ flash.output() }}
</p>
<p>
<label for="name">Name:</label><br>
{{ form.render('name') }}
</p>
<p>
{{ form.render('recaptcha') }}
</p>
<p>
{{ submit_button('Absenden') }}
</p>
{{ endform() }}

In der Datei app/views/index/success.volt hingegen wird nur der Wert des übermittelten Formular-Felds sowie ein Zurück-Button dargestellt.

<h1>Hallo {{name}}!</h1>
<p>{{ link_to(null, 'Zurück') }}</p>

Zusammenfassung

Das war’s auch schon: Ruft Eure Phalcon-Anwendung mit ReCaptcha-Implementierung im Browser auf und testet ob alles funktioniert. Das gesamte Projekt steht euch zusätzlich als Begleitmaterial auf GitHub zur Verfügung:

  • In der master-Branch findet ihr die voll funktionsfähige und einsatzbereite Anwendung
  • In der develop-Branch findet ihr das Grundgerüst zum selbst programmieren

Viel Spaß!

Hinterlasse einen Kommentar