Kategorien
Amazon AWS

APIs erstellen mit AWS API Gateway

Amazon API Gateway ist eine Service mit dem man professionelle APIs erstellen kann, welche

  • skalieren
  • sich um die Authentifizierung kümmern
  • serverless sein können zu AWS Labmda oder einem AWS Datern Speicher
  • aber auch über HTTP(S) zu einer EC2 Instanz weiterleiten können
mögliche verbindbare serverless Services
serverless Datenbank Funktionalität
serverless Website Hosting

Das AWS API Gateway kann den Request validieren, verändern und auch beantworten/abbrechen um Traffic zu sparen.

Zur Authentifizierung können verschiedene Methoden verwendet werden über JWT Token, Basic Auth, Custom HTTP URLs und eigene Lambda Funktion.

https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html

AWS Cognito zur Authentifizierung und User Management

Man kann aus der Schnittstelle ein SDK generieren, welches die Client zur Integration verwenden können und die Authentifizierung erleichtern. Derzeit werden unterstützt:

  • Java
  • Android
  • iOS
  • JavaScript
  • Ruby

https://docs.aws.amazon.com/de_de/apigateway/latest/developerguide/how-to-generate-sdk-console.html

Erstellen eines SDK für Clients zum einbinden der Schnittstelle

Alles Requests/Responses können gelogt werden und analysiert werden in AWS CloudWatch.

Die CORS Regeln können damit verwaltet werden.

Die API lässt sich mit Hilfe von Open API/Swagger 3.0 definieren.

Es können neben REST/HTTP auch Websocket APIs erstellt werden.

Canary Release Möglichkeit: Es werden nur 10% der Requests auf den neu releasten Endpunkt, um zu schauen, ob soweit alles funktioniert:

https://docs.aws.amazon.com/apigateway/latest/developerguide/canary-release.html

Preis-Übersicht:

https://aws.amazon.com/de/api-gateway/pricing/

Empfohlene Videos:

Kategorien
JavaScript

Funktionale Programmierung mit JavaScript

JavaScript ist keine funktionale Programmiersprache, aber die wichtigsten Prinzipien der funktionalen Programmierung lassen sich trotzdem beim Programmieren an einigen Stellen anwenden.

Diese Prinzipien sind u.a.:

  1. Funktionen haben Inputs und Outputs, aber keine Nebenwirkungen. Sie bearbeiten keine Daten, die ihnen nicht explizit übergeben wurden
  2. Variablen werden nicht verändert (Immortabilität)
  3. Funktionen höherer Ordnung dienen zur Schachtelung von Funktionen. Als Input (Parameter) von Funktionen werden wiederum Funktionen verwendet

An den folgende Beispielen und sehr praktischen Array Methoden soll der Unterschied zwischen funktionaler und nicht funktionaler Programmierung gezeigt werden:

forEach

Die Array methode forEach ermöglicht es funktional über ein Array zu iterieren, ohne eine sich verändernde Variable i zu verwenden.

// Beispiel alle Einträge in companies auf der Konsole ausgeben

//nicht funktional
for(let i = 0; i < companies.length; i++) {
   console.log(companies[i]);
}

//funktional
companies.forEach(function(company) {
  console.log(company);
});

filter

Die Array Methode filter entfernt Einträge aus einem Array, die nicht der übergebenen Bedingung entsprechen und gibt diese zurück. Man beachte, dass das ursprüngliche Array nicht verändert wird und die filter Mezhode selbst ein Funktion höherer Ordnung ist, weil als Parameter eine Funktion übergeben wird.

Kategorien
GIT

GIT mit SSH Verbindung unter Windows mit Ubuntu WSL2 einrichten

Um eine sichere Kommunikation mit einem GIT Repository über SSH einzurichten, muss man unter Windows 10 folgender Maßen vorgehen.

  1. Einen SSH Schlüssel generieren (private und publid), dieser wird automatisch in das Vezeichnis ~/.ssh (Home Verzeichnis des Users) gelegt.
ssh-keygen -o

2. Der public key muss dann hinterlegt werden beim GIT repository. Dies passiert meist über eine Web GUI. Der private Key verlässt nie die Person, die den Key generiert hat, ansonsten ist die Sicherheit nicht gegeben.

Der private Key muss mindestens die Dateirechte 600 haben, damit nur der Inhaber Darauf Zugriff hat, anosnten verweigert der ssh-agent die Zusammenarbeit und weißt auf die falschen Zugriffsrechte zu.

3. Eintragen der Verbindungsdaten in die ssh config Datei ~/.ssh/config

Host github.com
IdentityFile ~/.ssh/.ssh/my_host_public_key

Bei falschen Zugriffsrechten des private Keys erscheint die Meldung:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/user/.ssh/my_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

Die Zugriffsrechte 644 sind zu freigiebig. Hier sind angemessener 600 Rechte:

chmod 600 /home/user/.ssh/my_key

4. privaten SSH Key dem SSH Agent mitteilen:

ssh-add ~/.ssh/my_host_private_key

5. Test der SSH Verbindung (optional). Hinweis: Hier muss auch die Subdomain hinter dem @ verwendet werden. Es erscheint dann eine Willkommensnachricht bei Erfolg.

ssh -T git@github.com

6. GIT clone mit SSH

git clone git@github.com:sample-username/sample-repo.git
Kategorien
Docker

Docker Windows Port freigeben

Wenn man in Docker unter Windows die Fehlermeldung bekommt:

Error response from daemon: Ports are not available: listen tcp 0.0.0.0:12345: bind: An attempt was made to access a socket in a way forbidden by its access permissions.

Dann muss der Port 12345 freigeben werden:

Dazu muss man auf der Powsershell Konsole mit Admin Rechten erstmal checken, welche Ports schon freiegeben wurden:

netsh interface ipv4 show excludedportrange protocol=tcp

Wenn der Port in den Port Ranges nicht vorhanden ist, kann er folgender Maßen hinzugefügt werden:
  1. Hyper-V ausschalten (und PC neustarten danach)

dism.exe /Online /Disable-Feature:Microsoft-Hyper-V

2.Port hinzufügen:

netsh int ipv4 add excludedportrange protocol=tcp startport=12345 numberofports=1

3. Hyper-V wieder aktivieren (und PC neustarten danach)

dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /All

Kategorien
PHP

PHP-FFMpeg resize Video

Um mit PHP-FFMpeg ein Video auf eine maximale Größe und Breite zu resizen kann man folgenden Code verwenden:

<?php

namespace App\Core\Media;

use FFMpeg\Coordinate\Dimension;
use FFMpeg\FFMpeg;
use FFMpeg\Filters\Video\ResizeFilter;
use FFMpeg\Format\Video\X264;
use FFMpeg\Media\Video;

class VideoManager
{

    /**
     * @var FFMpeg
     */
    private $ffmpeg;

    /**
     * @var int
     */
    private $videoMaxHeight;

    /**
     * @var int
     */
    private $videoMaxWidth;

    /**
     * @var Video|null
     */
    private $video;

    /**
     * @var string|null
     */
    private $videoPath;

    /**
     * @param FFMpeg $ffmpeg
     * @param int $videoMaxHeight
     * @param int $videoMaxWidth
     */
    public function __construct(
        FFMpeg $ffmpeg,
        int $videoMaxHeight,
        int $videoMaxWidth
    )
    {
        $this->ffmpeg = $ffmpeg;
        $this->videoMaxHeight = $videoMaxHeight;
        $this->videoMaxWidth = $videoMaxWidth;
    }

    /**
     * @param string|null $videoPath
     * @return VideoManager
     */
    public function setVideoPath(?string $videoPath): VideoManager
    {
        $this->videoPath = $videoPath;
        if (!file_exists($videoPath)) {
            throw new \Exception('video does not exists:' . $videoPath);
        }
        $this->video = $this->ffmpeg->open($videoPath);

        return $this;
    }



    /**
     * @return int
     */
    public function getHeight(): int
    {
        return $this->video->getStreams()->first()->getDimensions()->getHeight();
    }

    /**
     * @return int
     */
    public function getWidth(): int
    {
        return $this->video->getStreams()->first()->getDimensions()->getWidth();
    }

    /**
     * @return void
     */
    public function formatH264Codec()
    {
        $format = new X264();

        $tmpDirectory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'video_format' . DIRECTORY_SEPARATOR;
        if (!is_dir($tmpDirectory)) {
            mkdir($tmpDirectory);
        }

        $tmpFilePath = $tmpDirectory . uniqid(time()) . '.mp4';

        $this->resizeVideo();

        $format
            ->setVideoCodec('libx264')
         ;

        $this->video->save($format, $tmpFilePath);

        // replace with encoded file
        unlink($this->videoPath);
        copy($tmpFilePath, $this->videoPath);

        //reset ffmpeg
        $this->ffmpeg = FFMpeg::create();
        $this->video = $this->ffmpeg->open($this->videoPath);
    }

    /**
     * @return void
     */
    protected function resizeVideo()
    {
        $width  = $this->getWidth();
        $height = $this->getHeight();

        if ($width > $this->videoMaxWidth || $height > $this->videoMaxHeight) {
            $factorWidth = $width / $this->videoMaxWidth;
            $factorHeight = $height / $this->videoMaxHeight;

            if ($factorWidth > $factorHeight) {
                $width = $width / $factorWidth;
                $height = $height / $factorWidth;
                $mode = ResizeFilter::RESIZEMODE_SCALE_WIDTH;
            } else {
                $width = $width / $factorHeight;
                $height = $height / $factorHeight;
                $mode = ResizeFilter::RESIZEMODE_SCALE_HEIGHT;
            }

            //round to the nearest odd number: ffmpeg otherwise throws an error
            $height = $this->roundToNextOddNumber($height);
            $width  = $this->roundToNextOddNumber($width);

            $this->video->filters()->resize(
                new Dimension($width, $height),
                $mode
            );
        }
    }

    /**
     * @param float $number
     * @return int
     */
    private function roundToNextOddNumber(float $number): int
    {
        $number = ceil($number); // Round up decimals to an integer
        if($number % 2 == 1) $number++;

        return $number;
    }
}

Usage:

$videoManager = new VideoManager(FFMpeg\FFMpeg::create(), 200, 300);
$videoManager->setVideoPath('/path/to/video.dat');
$this->videoManager->formatH264Codec();
Kategorien
PHP Symfony Testing

Symfony System-Test für valide Konfiguration der Umgebungen

Es gibt in Symfony die Möglichkeit mehrere Umgebungen (Environments) anzulegen und verschiedenartig zu konfigurieren. Das Problem ist, dass die automatisierten Tests immer gegen die Test-Umgebung und somit auch gegen die Test-Konfiguration gemacht werden.

Wie kann man sicher gehen, dass die produktive Konfiguration valide ist und dies mit einem automatisierten Test absichern?

Die Antwort ist sehr einfach, sollte eine Umgebungs-Konfiguration syntaktisch falsch sein, schlägt der Test fehl:

<?php

namespace App\Tests\System;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class BootKernelTest extends WebTestCase
{

    /**
     * @return array
     */
    public function dataProviderTestBootKernel(): array
    {
        return [
            'dev' => ['dev'],
            'test' => ['test'],
            'prod' => ['prod'],
        ];
    }

    /**
     * the test would fail if the environment config is wrong
     *
     * @dataProvider dataProviderTestBootKernel
     *
     * @param string $environment
     * @return void
     */
    public function testBootKernel(string $environment)
    {
        $kernel = $this->bootKernel(['environment' => $environment]);

        $this->assertNotEmpty($kernel);
    }

}

Kategorien
Amazon AWS

FFmpeg installieren auf Amazon Linux 2

Mit folgenden Befehlen kann man ffmpeg unter Amazon Linux 2 installieren:

sudo su
curl -o /tmp/ffmpeg.tar.xz https://www.johnvansickle.com/ffmpeg/old-releases/ffmpeg-4.2.2-amd64-static.tar.xz
tar -xvf /tmp/ffmpeg.tar.xz -C /usr/local/bin
ln -s /usr/local/bin/ffmpeg-4.2.2-amd64-static/ffmpeg /usr/bin/ffmpeg
ln -s /usr/local/bin/ffmpeg-4.2.2-amd64-static/ffprobe /usr/bin/ffprobe
Kategorien
Amazon AWS WordPress

WordPress Bitnami Banner entfernen auf AWS AMI

Um den Bitnami Banner entfernen zu können, soll man per SSH einen Konsolenbefehl ausführen:

sudo /opt/bitnami/apps/wordpress/bnconfig --disable_banner 1

dies führte bei mir zu einer Fehlermeldung, dass die Datei bnconfig nicht vorhanden ist:

sudo: /opt/bitnami/apps/wordpress/bnconfig: command not found

Die Ursache ist, dass die Datei standradmäßig erst deaktiviert ist, es gibt eine /opt/bitnami/apps/wordpress/bnconfig.disabled

Diese muss aktiviert werden, indem sie umbenannt wird nach bnconfig:

sudo mv /opt/bitnami/apps/wordpress/bnconfig.disabled /opt/bitnami/apps/wordpress/bnconfig

Danach kann der Banner erfolgreich entfernt werden:

sudo /opt/bitnami/apps/wordpress/bnconfig --disable_banner 1
Kategorien
CSS HTML5

Arial kostenlos als Webfont einbinden auf einer Webseite

Wenn man gern Arial als Schriftart auf seiner Webseite einbinden will und möchte, dass auch alle Besucher diese Schriftart verwenden sollen, auch die, die es nicht installiert haben, muss man den Font als Webfont einbinden.

Das Problem ist, dass Arial nicht frei verfügbar ist, sondern eine Lizenz dafür erworben werden muss: kostenpflichtiger Download.

Wenn man gern ohne Bezahlung Arial verwenden will, dann kann man einfach die Liberation Sans als Ersatz nehmen, welche fast genauso aussieht und kostenlos ist: Download Liberation Sans.

Diese lässt sich dann als Webfont einbinden:

@font-face {
  font-family: liberation_sans;
  src: url('/assets/fonts/liberation_sans/LiberationSans-Regular.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

@font-face {
  font-family: liberation_sans;
  src: url('/assets/fonts/liberation_sans/LiberationSans-Bold.ttf') format('truetype');
  font-weight: bold;
  font-style: normal;
}

@font-face {
  font-family: liberation_sans;
  src: url('/assets/fonts/liberation_sans/LiberationSans-Italic.ttf') format('truetype');
  font-weight: normal;
  font-style: italic;
}


@font-face {
  font-family: liberation_sans;
  src: url('/assets/fonts/liberation_sans/LiberationSans-BoldItalic.ttf') format('truetype');
  font-weight: bold;
  font-style: italic;
}

body{
    font-family: liberation_sans;
}
Kategorien
Symfony

Symfony Cache mit Datenbank

Die Symfony Cache Komponente besitzt eine große Zahl von möglichen Adaptern zum Cachen von Informationen.

Zum Cachen in der Datenbank kann man den folgenden PdoAdapter für Doctrine verwenden und folgender Maßen konfigurieren:

#config/packages/framework.yaml
framework:
    cache:
        pools:
            app:
                adapter: AppCache
#config/services.yaml
AppCache:
  class: Symfony\Component\Cache\Adapter\PdoAdapter
  arguments:
    - '@doctrine.dbal.default_connection'

Damit erzeugt Symfony eine Datenbank Tabelle innerhalb der default Datenbank Verbindung für die Cache Einträge.

Dies hat besonders Performancegewinne und ist übersichtlicher im Vergleich zu  der Default-Filesystem-Variante. Besonders ist dies für eine Docker Umgebung zu empfehlen, weil das langsame Dateisystem nicht verwnedet werden muss.