Kategorie: PHP

CakePHP 3: Benutzername oder Email zum Anmelden mit AuthComponent verwenden

In den Einstellungen der AuthComponent lässt sich festlegen, welches Feld der Datenbank für das Login verwendet werden soll. Hier kann allerdings nur ein einzelner Wert angegeben werden (bspw. username oder email). Um jedoch bei der Eingabe des Logins sowohl Benutzername, als auch Email zu erlauben, kann man die Einstellung zur Laufzeit (also beim Aufruf des Controllers) anpassen und das entsprechende Feld setzen. Und zwar wie folgt:

src/Controller/AppController.php

use Cake\Controller\Controller;

class AppController extends Controller
{
    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Flash');
        $this->loadComponent('Auth', [
            'authenticate' => [
                'Form' => [
                    'fields' => ['username' => 'username', 'password' => 'password'],
                ]
            ],
        ]);
    }
}

src/Controller/UsersController.php

use App\Controller\AppController;
use Cake\Validation\Validation;

class UsersController extends AppController
{
    public function login()
    {
        if ($this->request->is('post')) {

            if (Validation::email($this->request->getData('username'))) {
                $this->Auth->config('authenticate', [
                    'Form' => [
                        'fields' => ['username' => 'email']
                    ]
                ]);
                $this->Auth->constructAuthenticate();
                $this->request->data['email'] = $this->request->getData('username');
            }

            $user = $this->Auth->identify();

            if ($user) {
                $this->Auth->setUser($user);
                return $this->redirect($this->Auth->redirectUrl());
            }

            $this->Flash->error(__('Invalid combination of username/email and password.'));
        }
    }
}

src/Template/Users/login.ctp

<php
echo $this->Flash->render('auth');
echo $this->Form->create();

echo $this->Form->input('username');
echo $this->Form->input('password');

echo $this->Form->button(__('Login'));
echo $this->Form->end();
?>

Fatal error: Call to undefined function bindtextdomain()

Fatal error: Call to undefined function bindtextdomain() in [...]

Tritt der Fehler auf, dann fehlt möglicherweise die PHP-Erweiterung Gettext. Diese kann in der php.ini aktiviert werden:

extension=php_gettext.dll

Ist diese Erweiterung noch nicht vorhanden, dann lässt sich diese unter macOS (am Beispiel von PHP7.0) über MacPorts installieren:

sudo port install php70-gettext

Apache neustarten:

sudo port unload apache2
sudo port load apache2

PHP: Wie bekommt man Gettext zum Laufen?

Zunächst erstellt man sich ein Verzeichnis, z.B. locales/, in dem die Übersetzungsdateien abgelegt werden. Die Verzeichnisstruktur sollte Unterverzeichnisse für jede Sprache, beispielsweise en/ für Englisch, de/ für Deutsch, usw. enthalten und wie folgt aufgebaut sein:

locales/
  de/
    LC_MESSAGES/
      default.po
      default.mo
  en/
    LC_MESSAGES/
      ...

In diese Verzeichnisse kommen dann die Übersetzungsdateien (*.mo, *.po). Wie diese aufgebaut sind bzw erstellt werden, soll an dieser Stelle nicht weiter erläutert werden.

Einbindung in PHP

So sieht die Einbindung von Gettext in PHP aus:

$locale = 'de_DE';
$directory = './locales'; // diesen Pfad entsprechend anpassen!
$domain = 'default';

setlocale(LC_ALL, $locale.'.utf8');  // 'de_DE.utf8' (wichtig: utf8 ohne '-'!)
putenv('LC_ALL='.$locale);
bindtextdomain($domain, $directory); // 'default', './locales'
textdomain($domain);                 // 'default'
bind_textdomain_codeset($domain, 'UTF-8');

Zu beachtende Punkte

Gettext funktioniert nicht wie gewünscht? Lokalisierung wird nicht angezeigt? Dies dann kann verschiedene Gründe haben. Hier ein paar Anmerkungen:

Der String in $locale muss eine gültige Lokalisierung sein, welche auch auf dem System zur Verfügung steht. Ist diese korrekt (bzw. existiert diese), dann gibt setlocale() true zurück, andernfalls false.

Im Fehlerfall sollte man also prüfen, ob das System die angegebene Lokalisierung auch bereitstellt. Das kann man der Ausgabe folgender Zeile entnehmen:

print_r(ResourceBundle::getLocales(''));

Das Encodings (UTF-8) muss bei setlocale() ohne jeglichen Bindestrich angegeben werden.

Die Angabe ‚default‘ bezieht sich auf die Domain, also den Dateinamen der *.mo-Datei. Die *.po-Datei werden übrigens nicht direkt von Gettext verwendet. Diese werden aber benötigt, um die *.mo-Dateien zu erstellen.

MacPorts: mehrere PHP-Versionen gleichzeitig

MacPorts unterstützt jegliche PHP-Versionen. Diese können auch ohne Probleme gleichzeitig installiert werden. Die Pakete werden in MacPorts unter php56, php70, php71, ... usw. gelistet. Die notwendigen Befehle, um eine einzelne Version zu installieren:

MacPorts aktualisieren:

sudo port selfupdate
sudo port upgrade outdated

PHP Version (beispielsweise PHP 7.0) und ggf. erforderliche Module installieren:

sudo port install php70
sudo port install php70-apache2handler
sudo port install php70-... (je nach erforderlichen Modulen)

Nun zum Aktivieren der gewünschten PHP-Version: hier muss beachtet werden, dass es einen Unterschied zwischen der Konsole und der Anwendung von PHP in Apache gibt! So aktiviert man die PHP-Version an den unterschiedlichen Stellen:

PHP für die Konsole aktivieren:

sudo port select php php70

Überprüfen kann man die Version in der Konsole mit php -v.

PHP für Apache aktivieren:
In der Datei /opt/local/apache2/conf/http.conf die folgende Zeile einfügen oder aktivieren.

#LoadModule php5_module modules/mod_php56.so
LoadModule php7_module modules/mod_php70.so

Überprüfen kann man die Version mit phpinfo() in einer einfachen PHP-Datei.

Apache Neustarten:

sudo port unload apache2
sudo port load apache2

Composer global verwenden

In der Dokumentation zu Composer wird erläutert, wie man global auf composer.phar zugreifen kann, ohne permanent php composer.phar ins Terminal eingeben zu müssen:

[…]

You can place the Composer PHAR anywhere you wish. If you put it in a directory that is part of your PATH, you can access it globally. On unix systems you can even make it executable and invoke it without directly using the php interpreter.

After running the installer following the Download page instructions you can run this to move composer.phar to a directory that is in your path:

mv composer.phar/usr/local/bin/composer

Note: If the above fails due to permissions, you may need to run it again with sudo.

Note: On some versions of OSX the /usr directory does not exist by default. If you receive the error „/usr/local/bin/composer: No such file or directory“ then you must create the directory manually before proceeding: mkdir -p /usr/local/bin.

Note: For information on changing your PATH, please read the Wikipedia article and/or use Google.

Now just run composer in order to run Composer instead of php composer.phar.

FastCGI und ‚Authorization‘ Header

FastCGI scheint in den Standardeinstellungen den Authorization Header zu entfernen. Um diesen dennoch nutzen zu können, gibt es verschiedene Möglichkeiten:

Über .htaccess mit:

RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.+)
RewriteRule ^(.*)$ $1 [E=HTTP_AUTHORIZATION:%1,PT]

Oder:

SetEnvIf Authorization (.+) HTTP_AUTHORIZATION=$1

Oder in der FastCGI Config:

FastCGIConfig -pass-header HTTP_AUTHORIZATION