epcqr/lib/qrcode.class.php

228 lines
6.6 KiB
PHP

<?php
/* Copyright (C) 2025 Eduard Wisch <data@data-it-solution.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file lib/qrcode.class.php
* \ingroup epcqr
* \brief QR-Code Generator mit lokalem Caching
*/
/**
* QRCode Generator Klasse
* Generiert QR-Codes und cached sie lokal für Wiederverwendung
*/
class QRCodeGenerator
{
private $db;
private $cacheDir;
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
global $conf;
$this->db = $db;
// Cache-Verzeichnis für QR-Codes
$this->cacheDir = $conf->epcqr->dir_output.'/qrcodes';
// Verzeichnis erstellen falls nicht vorhanden
if (!is_dir($this->cacheDir)) {
dol_mkdir($this->cacheDir);
}
}
/**
* Generiert einen EPC-QR-Code für SEPA-Überweisungen
*
* @param string $accountHolder Kontoinhaber Name
* @param string $iban IBAN
* @param string $bic BIC (optional)
* @param float $amount Betrag
* @param string $reference Verwendungszweck
* @return string|false Pfad zur generierten QR-Code-Datei oder false bei Fehler
*/
public function generateEPCQRCode($accountHolder, $iban, $bic, $amount, $reference)
{
// Eindeutigen Dateinamen generieren basierend auf Parametern
$hash = md5($accountHolder.$iban.$bic.$amount.$reference);
$filename = 'epc_'.$hash.'.png';
$filepath = $this->cacheDir.'/'.$filename;
// Prüfen ob QR-Code bereits cached ist
if (file_exists($filepath)) {
dol_syslog("QRCodeGenerator: QR-Code aus Cache geladen: ".$filepath, LOG_DEBUG);
return $filepath;
}
// QR-Code generieren
$qrData = $this->generateEPCData($accountHolder, $iban, $bic, $amount, $reference);
$result = $this->generateQRImage($qrData, $filepath);
if ($result) {
dol_syslog("QRCodeGenerator: QR-Code generiert: ".$filepath, LOG_DEBUG);
return $filepath;
}
dol_syslog("QRCodeGenerator: Fehler beim Generieren des QR-Codes", LOG_ERR);
return false;
}
/**
* Generiert einen generischen QR-Code aus beliebigem Text
*
* @param string $data Daten für QR-Code
* @param string $prefix Präfix für Dateinamen (default: 'qr')
* @return string|false Pfad zur generierten QR-Code-Datei oder false bei Fehler
*/
public function generateQRCode($data, $prefix = 'qr')
{
// Eindeutigen Dateinamen generieren
$hash = md5($data);
$filename = $prefix.'_'.$hash.'.png';
$filepath = $this->cacheDir.'/'.$filename;
// Prüfen ob QR-Code bereits cached ist
if (file_exists($filepath)) {
dol_syslog("QRCodeGenerator: QR-Code aus Cache geladen: ".$filepath, LOG_DEBUG);
return $filepath;
}
// QR-Code generieren
$result = $this->generateQRImage($data, $filepath);
if ($result) {
dol_syslog("QRCodeGenerator: QR-Code generiert: ".$filepath, LOG_DEBUG);
return $filepath;
}
dol_syslog("QRCodeGenerator: Fehler beim Generieren des QR-Codes", LOG_ERR);
return false;
}
/**
* Generiert EPC-Datenstring für SEPA-QR-Codes
*
* @param string $accountHolder Kontoinhaber Name
* @param string $iban IBAN
* @param string $bic BIC
* @param float $amount Betrag
* @param string $reference Verwendungszweck
* @return string EPC-Datenstring
*/
private function generateEPCData($accountHolder, $iban, $bic, $amount, $reference)
{
// EPC QR-Code Format (GiroCode Standard)
$epcData = array(
'BCD', // Service Tag
'002', // Version
'1', // Character set (1 = UTF-8)
'SCT', // Identification (SEPA Credit Transfer)
$bic, // BIC
$accountHolder, // Empfänger Name
$iban, // Empfänger IBAN
'EUR'.number_format($amount, 2, '.', ''), // Betrag
'', // Purpose (optional)
$reference, // Verwendungszweck
'' // Beneficiary to originator information (optional)
);
return implode("\n", $epcData);
}
/**
* Generiert QR-Code-Bild aus Daten
*
* Nutzt zunächst den externen Service, später kann dies durch
* eine native PHP-Implementierung ersetzt werden
*
* @param string $data Daten für QR-Code
* @param string $filepath Zielpfad für PNG-Datei
* @return bool true bei Erfolg, false bei Fehler
*/
private function generateQRImage($data, $filepath)
{
// Methode 1: Externe API (aktuell)
// TODO: Später durch native PHP-Generierung ersetzen
$url = 'https://qr.data-it-solution.de/generate?data='.urlencode($data).'&size=300';
// Bild von URL holen
$imageData = @file_get_contents($url);
if ($imageData === false) {
// Fallback: Versuche mit cURL
if (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$imageData = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || $imageData === false) {
return false;
}
} else {
return false;
}
}
// Bild speichern
$result = file_put_contents($filepath, $imageData);
return ($result !== false);
}
/**
* Löscht gecachte QR-Codes die älter als X Tage sind
*
* @param int $days Anzahl Tage (default: 30)
* @return int Anzahl gelöschter Dateien
*/
public function cleanCache($days = 30)
{
$deleted = 0;
$threshold = time() - ($days * 86400);
if (!is_dir($this->cacheDir)) {
return 0;
}
$files = scandir($this->cacheDir);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$filepath = $this->cacheDir.'/'.$file;
if (is_file($filepath) && filemtime($filepath) < $threshold) {
if (unlink($filepath)) {
$deleted++;
}
}
}
dol_syslog("QRCodeGenerator: ".$deleted." alte QR-Codes gelöscht", LOG_INFO);
return $deleted;
}
}