Kategorien
PHP Server Administration

PHP Skript als Windows-Dienst ausführen

Unter Windows lassen sich Skripte, die endlos laufen sollen mit PHP mittels eines Dienstes realisieren.

Dies hat den Vorteil, dass der Speicherverbrauch nicht mit der Zeit ins unendliche geht, bei endloser Skriptausführungen und eine Recovery und Restart Funktionalität implementiert werden kann, um den Dienst über lange Zeiträume am Laufen zu halten.

Außerdem erhält der Dienst vom Betriebsystem Events, wenn z.B. eine Shutdown ansteht, um sich rechtzeitig selber beenden zu können und keine korrupten Daten zu produzieren beim Abbruch in einer nicht atomaren Operation.

Um einen Windows Dienst anzulegen benötigt man die win32service PHP-Library.

Diese kann man hier downloaden und in der php.ini einbinden:

extension=php_win32service.dll

Dienst anlegen

Kategorien
PHP Server Administration

Windows 10 geplante Aufgabe für PHP Skript anlegen analog Crontab

Für wiederkehrende PHP Jobs kann man den Betriebsystem Scheduler verwenden, unter Linux ist das cron und unter Windows Aufgaben.

Um ein PHP Skript zu starten C:\foo\bar.php mittels der Aufgabenplanung jede Minute kann man unter Windows 10 und darunter wie folgt neue Aufgaben anlegen.

Unter Systemsteuerung -> Aufgabenplanung lassen sich neue Aufgaben verwalten:

Systemsteuerung -> Aufgabenplanung
Kategorien
PHP

PHP cURL verifizieren eines selbst-signierten FTPS Zertifikat

Leider kann man mit der PHP FTP Erweiterung keine SSL Zertifikate von FTPS Servern zu verifizieren, um Man-in-the-Middle Angriffe zu verhindern.

Es ist aber möglich über php-cURL das selbst signierte Zertifikat zu verifizieren:

public function checkFTPSCertificate(): bool
{
    $ftp_certificate = 'path/to/cert.crt'

    $ftp_server = 'ftp://foo.de/';
    $ftp_user = 'user';
    $ftp_password = 'password';

    $ch = curl_init();

    // curl_setopt($ch, CURLOPT_VERBOSE, '1');
    curl_setopt($ch, CURLOPT_URL, $ftp_server);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_USERPWD, $ftp_user . ':' . $ftp_password);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);


    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, '1'); // Überprüfung des Serverzertifikats
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, '2');
    curl_setopt($ch, CURLOPT_CAINFO , $ftp_certificate);
    curl_setopt($ch, CURLOPT_FTP_SSL, CURLFTPSSL_ALL);
    curl_setopt($ch, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_TLS);

    $result = curl_exec($ch);
    $error_no = curl_errno($ch);
    $error_msg = curl_error($ch);
    curl_close ($ch);
    return $error_no == 0 && empty($error_msg);
}
Kategorien
PHP 7

PHP: ftp_fget(): Entering Passive Mode (10,1,0,139,213,156).

Die Fehlermeldung:

 ftp_fget(): Entering Passive Mode (10,1,0,139,213,156)

bedeutet, dass der FTP Client eine neue passive Verbindung auf der IP 10.1.0.139 auf Port 213 * 256 + 156 = Port 54684 aufmachen soll.

Am einfachsten händelt man diese Situation, wenn man sich neu verbindet mit ftp_connect() und es nochmal versucht und eine passive Verbindung aufbaut mit ftp_pasv();

 

Kategorien
PHP Symfony

Gaufrette mit File Streams arbeiten

Um mit Gaufrette (Symfony Extension) auch Stream Operationen an Dateien durchführen zu können, kann man den etwas dürr dokumentierten Stream Wrapper verwenden.

Dazu konfiguriert man in der gaufrette.yaml:

knp_gaufrette:
    stream_wrapper: ~
    filesystems:
        backup1:
            adapter: backup

Und kann dann z.B. folgender Maßen eine csv. Datei schreiben:

$stream = fopen('gaufrette://backup1/datei.csv', 'w+');

fputcsv($stream, [1,2,3]);
Kategorien
PHP Symfony

Symfony Service ID dynamisch konfigurieren mittels Parameter

Wenn man gern in seiner Depnedency Injection Kofiguration (services.yml) die Service Injektionen dynamisch konfigurierbar machen will über die parameters.yml,

parameters:
    my_class: 'App\MyClass'

kann man dies mittels der Symfony Expression Language Komponente tun:

composer require symfony/expression-language

Dann kann man in der services.yml definieren:

services:
    App\Command\MyCommand:
      arguments:
        - '@=service(parameter("my_class"))'
Kategorien
PHP

Windows Composer Update Fatal error: Allowed memory size of 1610612736 bytes exhausted

Folgende Fehlermeldung hat mein Composer trotz unbegrenztem Speicher:

 composer update
 Loading composer repositories with package information
 Updating dependencies (including require-dev)

 VirtualAlloc() failed: [0x00000008] Zur Verarbeitung dieses Befehls sind nicht gen
 VirtualAlloc() failed: [0x00000008] Zur Verarbeitung dieses Befehls sind nicht gen

 Fatal error: Out of memory (allocated 1260388352) (tried to allocate 201326600 bytes) in phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/DependencyResolver/RuleSet.php on line 83

Wenn man unter Windows ein composer Update nicht mehr durchführen kann, obwohl man das Memory Limit auf unbegrenzt gesetzt hat, dann hat man ein Problem:

Das Windows-Xammp ist nur als 32 bit System erhältlich und kann nur 2GB Ram bereitstellen im Moment, eine weitere Erhöhung ist nicht möglich.

Die Lösung ist  Composer mit einem 64bit PHP auf der Konsole auszuführen (dies hat dann bis zu 4GB Memory).

  • Download von PHP x64 Version
  • entpacken und php.ini anlegen (umbennnen der php.ini-development)
  • memory Limit erhöhen in php.ini: memory_limit = -1
  • auf der Konsole ausführen:
"C:\php-7.2.12-nts-Win32-VC15-x64\php" C:\ProgramData\ComposerSetup\bin\composer.phar update
Kategorien
Symfony Yii Framework

Yii2 versus Symfony 4 – ein Framework Vergleich

Ich habe lange mit Yii und dem Symfony Framework gearbeitet und will versuchen im Folgenden die Unterschiede von beiden Frameworks aus Programmierer Sicht zu erläutern.

Konfiguration von Umgebungen

Beim Erstellen von Web-Anwendungen hat man typischer Weise mindestens 2 Umgebungen: Die Entwicklungsumgebung, auf der man Fehler sehen will und die Live Umgebung, wo dies nicht passieren soll. Dazu kommen Test-Umgebung zum Ausführen automatisierter Tests und vielleicht eine Staging Umgebung.

Symfony löst das sehr geschickt, mit .env Dateien und eigenen Ordnern innerhalb des Konfigurations-Ordners.

Bei Yii muss der Programmierer selber hand anlegen, um die richtige Konfiguration zu laden, es sind von Hause aus nur 3 (dev, prod, test) Umgebungen vorgsehen, danach wird es unübersichtlich.

Kategorien
PHP

PHP encode String zu Extended ASCII 8bit 255 Zeichen

Um auch Umlaute in ein Bit darzustellen, kann man den erweiterten ASCII Zeichensatz verwenden mit 255 Zeichen, der auch Umlaute enthält wie ä, ö, ü und ß.

Um dieses zu nutzen, kann man die folgende Funktion nutzen:

/**
 * @param string $string
 * @return string
 */
protected function asciiEncodeString(string $string): string
{
    $sourceEncoding = mb_detect_encoding($string);
    $destinationEncoding = 'CP437'; // Extended ASCII - Codepage 437
    $string = iconv($sourceEncoding, $destinationEncoding, $string);
    return $string;
}
Kategorien
PHP

UDP mit PHP Nachrichten senden und empfangen Beispiel

Mit PHP kann man über UDP auf dem eigenen Rechner sehr einfach Packete verschicken. Um dies zu testen, braucht man einen Sender und einen Empfänger. In dem Biepsiel kommunizieren beider über die lokale IP auf Port 20010. Die Beispiele müssen auf der Konsole ausgeführt werden.

Sender:

<?php
$address = '127.0.0.1';
$port = 20010;
$beat_period = 1;

$fp = stream_socket_client("udp://$address:$port", $errno, $errstr);
if (!$fp) {
 die("ERROR: $errno - $errstr");
}

while (true) {
 $message = sprintf(
 '%s send: %s'. PHP_EOL,
 date('c'),
 rand(0, 1000000)
 );
 fwrite($fp, $message);
 echo $message;

 sleep($beat_period);
}

Empfänger:

<?php

$address = '127.0.0.1';
$port = 20010;

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, $address, $port);

if ($socket === false) {
 throw new \RuntimeException(
 sprintf(
 'could not connect to socket address %s on port %s. Error: %s %s',
 $address,
 $port,
 socket_last_error(),
 socket_strerror(socket_last_error())
 )
 );
}

while (true){
 echo socket_read ($socket, 1024);
}