Kategorien
Amazon AWS Docker PHP 7

DockerFile PHP mit XDebug und Amazon Linux 2

Ein DockerFile für eine PHP 7.2. Umgebung mit XDebug für eine Symfony 4 Umgebung unter Amazon Linux 2:

FROM amazonlinux:2.0.20190823.1

RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

# install php
RUN amazon-linux-extras install -y php7.2
RUN yum install -y php-devel.x86_64 php-xml.x86_64 php-pecl-zip.x86_64  php-intl.x86_64

#install xdebug
RUN yum install -y gcc make
RUN yum install -y php-pear.noarch
RUN pecl install xdebug
RUN echo 'zend_extension=/usr/lib64/php/modules/xdebug.so' >> /etc/php.ini
Kategorien
PHP PHP 7 VBA Excel

PHP csv Datei mit Umlauten erstellen für Excel

Um eine csv-Datei zu erstellen, in der die Umlaute richtig kodiert sind, muss man in seinem Projekt, welches im Normalfall UTF-8 kodiert ist, die Umlaute nach UTF-16LE kodieren. Diese Kodierung kann von Windows und Mac angezeigt werden.

$file = fopen('file.csv', 'w');
foreach ($rows as $row) {
 $row = array_map(function($cell){
 return mb_convert_encoding($cell, 'UTF-16LE', 'UTF-8');
 }, $row);
 fputcsv($file, $row, ';');
}
fclose($file);
Kategorien
Amazon AWS Symfony

Monolog Logging für AWS Cloudwatch Logs konfigurieren

Damit die Logs schön formatiert aus einer Symfony 4 Anwendung in AWS Cloudwatch ankommen, muss man Monolog folgendermaßen konfigurieren:

# config/services.yaml
Monolog\Formatter\JsonFormatter:
    calls:
        - [includeStacktraces]

und

# config/packages/prod/monolog.yaml
monolog:
  handlers:
    main:
      type:  stream
      level: error
      path:  '%kernel.logs_dir%/error.log'
      formatter: Monolog\Formatter\JsonFormatter

Danach muss man der Cloudwatch Daemon konfigurieren:

# /etc/awslogs/awslogs.conf
[general]
# Path to the CloudWatch Logs agent's state file. The agent uses this file to maintain
# client side state across its executions.
state_file = /var/lib/awslogs/agent-state

[/var/www/html/var/log/error.prod.log]
datetime_format = [%Y-%m-%d H:%M:%S]
file = /var/www/html/var/log/error.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = test_group_name/error_log

und man erhält wunderbare (aggregierte) ErrorLog Informationen in Cloudwatch Logs Insight:

 

 

Kategorien
Symfony

Symfony Switftmailer Mail wird nicht gesendet

Mit dem folgende Befehl kann eine Testmail versendet werden mit Swiftmailer. Falls die Email nicht ankommt, sind die Switftmailer Parameter in config/packages/swiftmailer.yaml wahrscheinlich falsch:

php bin/console swiftmailer:email:send --help

Da die Email mit eine Queue versendet werden, sollte trotzdem in das error_log untersucht werden unter var/log/, darin fand sich bei mir der Grund für mein Versand Problem:

app.ERROR: Exception occurred while flushing email queue: Expected response code 250 but got code "554", with message "554 Message rejected: 
Email address is not verified. The following identities failed the check in region EU-WEST-1: email1, email2

 

Kategorien
Symfony

Symfony Sonata Redirect der Root URL in den Adminbereich

Wenn man den User bei der Eingabe im Browser ohne ein Pfad (www.foo.de) zum Adminbereich von Sonata (www.foo.de/admin) weiterleiten will, kann man dies sehr elegant mittels eines Symfony Redirects in der routing.yml tun:

index:
  path: /
  defaults:
    _controller: FrameworkBundle:Redirect:urlRedirect
    path: /admin
    permanent: true
Kategorien
Symfony

Tutorial: Symfony Administrations-Backend erstellen

In diesem Beitrag werde ich mit Symfony 4 eine Administartionsoberfläche mit Hilfe von Sonata erstellen und die einzelnen Schritte beschreiben.

1. Anlegen eines neuen Symfony Projektes

Mit composer kann man schnell ein neues Symfony Skeleton Projekt anlegen lassen:

composer create-project symfony/website-skeleton my-admin-demo

Das Skeleton Projekt enthält die wichtigsten Symfony Komponenten für eine Webapplikation sowie Doctrine.

Jetzt ist ein guter Zeitpunkt das Porjket in ein Versionierungsystem wie GIT einzuchecken und zum ersten mal zu committen.

Optional kann jetzt Symfony PHPUnit Bridge installiert werden, wenn Tests geschrieben werden sollen:

composer require phpunit --dev

Die Datenbank kann jetzt konfiguriert werden in der .env Datei:

DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name

Und mit folgendem Befehl angelegt werden:

php bin/console doctrine:database:create

2. Installation des SonataAdmin Bundles

Kategorien
PHPUnit Symfony

Call to undefined method PHPUnit\Util\ErrorHandler::handleError()

In Version 8.3 von PHPUnit gibt es leider die Methode handleError nicht mehr, deswegen kommt es bei meine Symfony Projekten zu Problemen.

Call to undefined method PHPUnit\Util\ErrorHandler::handleError()

Abhilfe schafft die Installation von PHPUnit 8.2:

composer require phpunit/phpunit:8.2 --dev
Kategorien
PHP PHP 7 Symfony

Gaufrette FTP Adapter rekursiv Verzeichnisse löschen

Um mit dem FTP Adapter von Gaufrette rekursiv Dateien und Unterverzeichnisse zu löschen kann man folgenden Trick anwenden um nicht in die Fehlermeldung zu geraten:

ftp_rmdir(): Directory not empty.

1. erst alle Dateien löschen

2. dann die tiefsten Verzeichnisse bis hin zu den obersten löschen:

/**
 * @param Filesystem $fileSystem
 */
function deleteAllFilesInDirectory(Filesystem $fileSystem)
{
    // delete files first, than directories
    foreach ($fileSystem->keys() as $key) {
        if (!$fileSystem->isDirectory($key)) {
            $fileSystem->delete($key);
        }
    }
    $keys = $fileSystem->keys();
    usort($keys, function (string $a, string $b){
        $aCount = substr_count($a, '/');
        $bCount = substr_count($b, '/');
        return $bCount <=> $aCount;
    });
    foreach ($keys as $key) {
        $fileSystem->delete($key);
    }
}
Kategorien
Symfony

Symfony FosUser Bundle eigene Password Policy anwenden

Um im SonataAdmin mit FosUser Bundle Modul eigene Regeln zu definieren für die Stärke der Passwörter, kann man die validation.xml überschreiben, indem man im Ordner src/Application/Sonata/UserBundle/Resources/config/ eine eigene validation.xml anlegt:

<?xml version="1.0" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
        http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">

    <class name="FOS\UserBundle\Model\User">

        <property name="plainPassword">
            <constraint name="NotBlank">
                <option name="message">fos_user.password.blank</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>ResetPassword</value>
                    <value>ChangePassword</value>
                </option>
            </constraint>
            <constraint name="Length">
                <option name="min">8</option>
                <option name="max">50</option>
                <option name="minMessage">fos_user.password.short</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>Profile</value>
                    <value>ResetPassword</value>
                    <value>ChangePassword</value>
                </option>
            </constraint>
            <constraint name="Regex">
                <option name="pattern">/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/</option>
                <option name="message">Das Passwort muss mindestens 8 Zeichen haben, eine Zahl, Groß und Kleinschreibung enthalten.</option>
                <option name="groups">
                    <value>Registration</value>
                    <value>Profile</value>
                    <value>ResetPassword</value>
                    <value>ChangePassword</value>
                </option>
            </constraint>
        </property>
    </class>
</constraint-mapping>
Kategorien
Symfony

Symfony Brute-Force Guard für SonataAdmin erstellen

Für das SonataAdmin Bundle gibt es die Möglichkeit über Symofny Guards eigene Logik in den Loginprozess einzubauen, wie z.B.:

  • Abwehr von Brute Force Angriffen durch eine maximale Anzahl von Login-Versuchen

In dem folgenden Beispiel habe ich einen Guard konfiguriert für den Administrationsbereich, der mitzählt, wie oft sich ein User falsch eingeloggt hat.

Der UserManager muss dann die Logik enthalten, um bei jedem User die Anzahl der Logins mitzuzählen und ihn ggf. auch zu bannen für eine bestimmte Zeit.