| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/clients/client2/web20/web/wp-content/plugins/dgt-verkehrsmonitor/cli/ |
Upload File : |
<?php
/**
* Facebook-Post mit Tagesbild generieren.
*
* Aufruf: php facebook-post.php [YYYY-MM-DD] [--publish]
*
* @package dgt-verkehrsmonitor
*/
if ( PHP_SAPI !== 'cli' ) {
exit( 'Nur per CLI.' );
}
require_once dirname( __DIR__, 4 ) . '/wp-load.php';
global $wpdb;
$date = isset( $argv[1] ) ? $argv[1] : gmdate( 'Y-m-d', strtotime( '-1 day' ) );
$t_inc = dgt_vm_table( 'incidents' );
$t_ds = dgt_vm_table( 'daily_stats' );
$t_ss = dgt_vm_table( 'substance_stats' );
$stats = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$t_ds} WHERE stat_date = %s AND bundesland = '_all'",
$date
) );
if ( ! $stats || ! $stats->total ) {
fwrite( STDERR, "Keine Daten für {$date}.\n" );
exit( 1 );
}
$subs = $wpdb->get_results( $wpdb->prepare(
"SELECT substanz, anzahl FROM {$t_ss} WHERE stat_date = %s AND bundesland = '_all' ORDER BY anzahl DESC",
$date
) );
$bl_ranking = $wpdb->get_results( $wpdb->prepare(
"SELECT bundesland, total FROM {$t_ds} WHERE stat_date = %s AND bundesland != '_all' ORDER BY total DESC LIMIT 5",
$date
) );
$top_bak = $wpdb->get_row( $wpdb->prepare(
"SELECT ai_headline, bak_wert, stadt FROM {$t_inc} WHERE source_date = %s AND status = 'publiziert' AND bak_wert IS NOT NULL ORDER BY bak_wert DESC LIMIT 1",
$date
) );
$date_de = strftime_de( $date );
/* ─── Bild generieren ─────────────────────────────────── */
$w = 1200;
$h = 800;
$img = imagecreatetruecolor( $w, $h );
imagealphablending( $img, true );
imagesavealpha( $img, true );
// ─── Farben (invertiert: dunkler Hintergrund) ──────
$c_bg = imagecolorallocate( $img, 11, 22, 40 );
$c_white = imagecolorallocate( $img, 255, 255, 255 );
$c_dark = imagecolorallocate( $img, 255, 255, 255 );
$c_teal = imagecolorallocate( $img, 42, 157, 143 );
$c_teal_dk = imagecolorallocate( $img, 28, 110, 100 );
$c_red = imagecolorallocate( $img, 239, 68, 68 );
$c_green = imagecolorallocate( $img, 52, 180, 120 );
$c_amber = imagecolorallocate( $img, 245, 178, 30 );
$c_blue = imagecolorallocate( $img, 80, 155, 230 );
$c_muted = imagecolorallocate( $img, 148, 163, 184 );
$c_card_sh = imagecolorallocatealpha( $img, 0, 0, 0, 60 );
$c_card_bg = imagecolorallocatealpha( $img, 30, 41, 59, 0 );
$c_glass = imagecolorallocatealpha( $img, 40, 55, 80, 50 );
$c_bar = imagecolorallocate( $img, 30, 41, 59 );
// ─── Fonts ──────
$f_black = '/usr/share/fonts/truetype/lato/Lato-Black.ttf';
$f_bold = '/usr/share/fonts/truetype/lato/Lato-Bold.ttf';
$f_semi = '/usr/share/fonts/truetype/lato/Lato-Semibold.ttf';
$f_med = '/usr/share/fonts/truetype/lato/Lato-Medium.ttf';
$f_reg = '/usr/share/fonts/truetype/lato/Lato-Regular.ttf';
$f_it = '/usr/share/fonts/truetype/lato/Lato-Italic.ttf';
// ─── Hintergrund ──────
imagefill( $img, 0, 0, $c_bg );
// ─── Polizeibild (oben rechts) ──────
$hero_path = dirname( __DIR__, 4 ) . '/wp-content/uploads/2026/06/verkehrsmonitor-deutschland.webp';
if ( function_exists( 'imagecreatefromwebp' ) && file_exists( $hero_path ) ) {
$hero = @imagecreatefromwebp( $hero_path );
if ( $hero ) {
$hw = imagesx( $hero );
$hh = imagesy( $hero );
$tw = 520;
$th = (int) ( $hh * $tw / $hw );
if ( $th > 300 ) {
$th = 300;
$tw = (int) ( $hw * $th / $hh );
}
imagecopyresampled( $img, $hero, $w - $tw, 0, 0, 0, $tw, $th, $hw, $hh );
imagedestroy( $hero );
for ( $i = 0; $i < 250; $i++ ) {
$x = $w - $tw + $i;
$alp = (int) ( 127 * $i / 250 );
$fc = imagecolorallocatealpha( $img, 11, 22, 40, $alp );
imageline( $img, $x, 0, $x, $th, $fc );
}
}
}
// ─── Deko-Blasen ──────
$bc1 = imagecolorallocatealpha( $img, 42, 157, 143, 70 );
$bc2 = imagecolorallocatealpha( $img, 42, 157, 143, 85 );
imagefilledellipse( $img, 628, 20, 16, 16, $bc1 );
imagefilledellipse( $img, 648, 38, 10, 10, $bc2 );
imagefilledellipse( $img, 640, 10, 7, 7, $bc2 );
imagefilledellipse( $img, 660, 26, 12, 12, $bc1 );
imagefilledellipse( $img, 622, 42, 6, 6, $bc2 );
imagefilledellipse( $img, 652, 52, 5, 5, $bc2 );
// ─── Header ──────
imagettftext( $img, 18, 0, 40, 40, $c_teal, $f_black, 'VERKEHRSMONITOR DEUTSCHLAND' );
imagettftext( $img, 14, 0, 40, 65, $c_muted, $f_reg, $date_de );
// ─── Hauptzahl mit Icon ──────
$mcx = 95;
$mcy = 148;
imagefilledellipse( $img, $mcx, $mcy, 82, 82, $c_teal );
// Flasche.
imagefilledrectangle( $img, $mcx - 4, $mcy - 22, $mcx + 0, $mcy - 12, $c_white );
imagefilledrectangle( $img, $mcx - 9, $mcy - 12, $mcx + 5, $mcy + 14, $c_white );
imagefilledellipse( $img, $mcx - 2, $mcy + 14, 14, 5, $c_white );
// Glas.
imagefilledrectangle( $img, $mcx + 10, $mcy - 6, $mcx + 22, $mcy + 14, $c_white );
imagefilledrectangle( $img, $mcx + 8, $mcy - 8, $mcx + 24, $mcy - 5, $c_white );
$num_str = (string) $stats->total;
imagettftext( $img, 72, 0, 150, 180, $c_dark, $f_black, $num_str );
$nb = imagettfbbox( 72, 0, $f_black, $num_str );
$nr = 160 + $nb[2];
imagettftext( $img, 28, 0, $nr, 135, $c_dark, $f_black, 'Alkohol- &' );
imagettftext( $img, 28, 0, $nr, 168, $c_dark, $f_black, 'Drogenfahrten' );
imagettftext( $img, 17, 0, $nr, 195, $c_teal, $f_semi, 'gestern in Deutschland' );
// ─── 4 Stat-Karten ──────
$cy = 220;
$ch = 115;
$cw = 265;
$cg = 18;
$stat_cards = array(
array( 'ic' => $c_red, 'n' => $stats->alkohol, 'l' => 'Alkohol', 's' => 'Fahrten unter Alkoholeinfluss', 't' => 'bottle' ),
array( 'ic' => $c_green, 'n' => $stats->drogen, 'l' => 'Drogen', 's' => 'Fahrten unter Drogeneinfluss', 't' => 'leaf' ),
array( 'ic' => $c_amber, 'n' => $stats->unfaelle, 'l' => 'Unfälle', 's' => 'mit Alkohol oder Drogen', 't' => 'car' ),
array( 'ic' => $c_blue, 'n' => $stats->fs_entzogen, 'l' => 'Führerscheine', 's' => 'wurden entzogen', 't' => 'card' ),
);
foreach ( $stat_cards as $i => $sc ) {
$cx = 30 + $i * ( $cw + $cg );
// Schatten.
imagefilledroundedrect( $img, $cx + 3, $cy + 3, $cx + $cw + 3, $cy + $ch + 3, 14, $c_card_sh );
// Karte (Glas-Effekt).
imagefilledroundedrect( $img, $cx, $cy, $cx + $cw, $cy + $ch, 14, $c_card_bg );
// Glas-Highlight oben.
imagefilledroundedrect( $img, $cx, $cy, $cx + $cw, $cy + 40, 14, $c_glass );
// Icon-Kreis.
$icx = $cx + 38;
$icy = $cy + 48;
imagefilledellipse( $img, $icx, $icy, 48, 48, $sc['ic'] );
draw_card_icon( $img, $icx, $icy, $sc['t'], $c_white );
// Zahl.
imagettftext( $img, 38, 0, $cx + 72, $cy + 58, $c_dark, $f_black, (string) $sc['n'] );
// Label.
imagettftext( $img, 14, 0, $cx + 72, $cy + 78, $sc['ic'], $f_bold, $sc['l'] );
// Sub.
imagettftext( $img, 10, 0, $cx + 15, $cy + 102, $c_muted, $f_reg, $sc['s'] );
}
// ─── Promille-Balken ──────
$py = 355;
$ph = 46;
$bw = 555;
if ( $stats->max_bak ) {
// Balken 1: Höchster Promillewert.
imagefilledroundedrect( $img, 30, $py, 30 + $bw, $py + $ph, 10, $c_bar );
draw_trend_arrow( $img, 50, $py + 23, $c_teal );
imagettftext( $img, 12, 0, 75, $py + 29, $c_muted, $f_reg, 'Höchster Promillewert' );
$bak_s = number_format( (float) $stats->max_bak, 2, ',', '.' ) . ' ‰';
$bb = imagettfbbox( 24, 0, $f_black, $bak_s );
imagettftext( $img, 24, 0, 30 + $bw - 22 - $bb[2], $py + 33, $c_teal, $f_black, $bak_s );
// Balken 2: Durchschnitt.
if ( $stats->avg_bak ) {
$bx2 = 30 + $bw + 25;
imagefilledroundedrect( $img, $bx2, $py, $bx2 + $bw, $py + $ph, 10, $c_bar );
draw_trend_arrow( $img, $bx2 + 20, $py + 23, $c_teal );
imagettftext( $img, 12, 0, $bx2 + 45, $py + 29, $c_muted, $f_reg, 'Durchschnittlicher Promillewert' );
$avg_s = number_format( (float) $stats->avg_bak, 2, ',', '.' ) . ' ‰';
$ab = imagettfbbox( 24, 0, $f_black, $avg_s );
imagettftext( $img, 24, 0, $bx2 + $bw - 22 - $ab[2], $py + 33, $c_teal, $f_black, $avg_s );
}
}
// ─── Top Bundesländer ──────
$bly = 460;
imagettftext( $img, 16, 0, 40, $bly, $c_teal, $f_black, 'TOP BUNDESLÄNDER' );
$bl_names = array(
'nordrhein-westfalen' => 'NRW',
'baden-wuerttemberg' => 'Baden-Württemberg',
'bayern' => 'Bayern',
'niedersachsen' => 'Niedersachsen',
'hessen' => 'Hessen',
'rheinland-pfalz' => 'Rheinland-Pfalz',
'hamburg' => 'Hamburg',
'berlin' => 'Berlin',
'sachsen' => 'Sachsen',
'thueringen' => 'Thüringen',
'schleswig-holstein' => 'Schleswig-Holstein',
'brandenburg' => 'Brandenburg',
'sachsen-anhalt' => 'Sachsen-Anhalt',
'mecklenburg-vorpommern' => 'Meckl.-Vorpommern',
'saarland' => 'Saarland',
'bremen' => 'Bremen',
);
$max_bl = $bl_ranking ? (int) $bl_ranking[0]->total : 1;
$bly += 35;
foreach ( $bl_ranking as $i => $bl ) {
$name = isset( $bl_names[ $bl->bundesland ] ) ? $bl_names[ $bl->bundesland ] : $bl->bundesland;
$bar_w = max( 12, (int) ( ( $bl->total / $max_bl ) * 280 ) );
imagettftext( $img, 13, 0, 40, $bly + 5, $c_dark, $f_bold, ( $i + 1 ) . '.' );
imagettftext( $img, 13, 0, 68, $bly + 5, $c_dark, $f_reg, $name );
imagefilledroundedrect( $img, 245, $bly - 10, 245 + $bar_w, $bly + 10, 5, $c_teal );
imagettftext( $img, 13, 0, 255 + $bar_w, $bly + 5, $c_dark, $f_bold, (string) $bl->total );
$bly += 34;
}
// ─── QR-Code ──────
$qx = 940;
$qy = 475;
$qs = 170;
$qr_cache = dirname( __DIR__ ) . '/assets/qr-verkehrsmonitor.png';
if ( ! file_exists( $qr_cache ) ) {
$qr_api = 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&format=png&data=';
$qr_data = @file_get_contents( $qr_api . urlencode( 'https://www.drogentest-online.de/verkehrsmonitor/' ) );
if ( $qr_data ) {
$assets_dir = dirname( __DIR__ ) . '/assets';
if ( ! is_dir( $assets_dir ) ) {
mkdir( $assets_dir, 0755, true );
}
file_put_contents( $qr_cache, $qr_data );
}
}
if ( file_exists( $qr_cache ) ) {
$qr_img = @imagecreatefrompng( $qr_cache );
if ( $qr_img ) {
imagefilledroundedrect( $img, $qx - 10, $qy - 10, $qx + $qs + 10, $qy + $qs + 10, 10, $c_white );
imagecopyresampled( $img, $qr_img, $qx, $qy, 0, 0, $qs, $qs, imagesx( $qr_img ), imagesy( $qr_img ) );
imagedestroy( $qr_img );
}
}
imagettftext( $img, 20, 0, $qx + 10, $qy - 30, $c_dark, $f_it, 'Mehr Infos' );
// ─── Footer ──────
$fy = $h - 65;
$fh = 50;
imagefilledroundedrect( $img, 15, $fy, $w - 15, $fy + $fh, 12, $c_teal );
// Icon links.
imagefilledellipse( $img, 52, $fy + 25, 28, 28, $c_teal_dk );
imagefilledrectangle( $img, 46, $fy + 17, 58, $fy + 33, $c_white );
imageline( $img, 46, $fy + 22, 58, $fy + 22, $c_teal_dk );
imageline( $img, 46, $fy + 27, 58, $fy + 27, $c_teal_dk );
imagettftext( $img, 12, 0, 75, $fy + 30, $c_white, $f_reg, 'Mehr Statistiken, Ratgeber & Hilfe' );
// URL (dunkler Pill).
$url_text = 'drogentest-online.de/verkehrsmonitor';
$url_bb = imagettfbbox( 13, 0, $f_bold, $url_text );
$url_w = $url_bb[2] - $url_bb[0] + 36;
$url_x = (int) ( ( $w - $url_w ) / 2 );
imagefilledroundedrect( $img, $url_x, $fy + 6, $url_x + $url_w, $fy + $fh - 6, 8, $c_teal_dk );
imagettftext( $img, 13, 0, $url_x + 18, $fy + 32, $c_white, $f_bold, $url_text );
imagettftext( $img, 11, 0, $w - 285, $fy + 30, $c_white, $f_reg, 'Quelle: Polizeiberichte - KI Analyse' );
// ─── Speichern ──────
$out_dir = dirname( __DIR__ ) . '/assets';
if ( ! is_dir( $out_dir ) ) {
mkdir( $out_dir, 0755, true );
}
$out_path = $out_dir . '/fb-post-' . $date . '.png';
imagepng( $img, $out_path, 5 );
imagedestroy( $img );
echo "Bild: {$out_path}\n\n";
/* ─── Post-Text ───────────────────────────────────────── */
$emoji_warn = "\xE2\x9A\xA0\xEF\xB8\x8F";
$emoji_bar = "\xF0\x9F\x93\x8A";
$emoji_car = "\xF0\x9F\x9A\x97";
$emoji_link = "\xF0\x9F\x94\x97";
$emoji_beer = "\xF0\x9F\x8D\xBA";
$emoji_pill = "\xF0\x9F\x92\x8A";
$text = "{$emoji_warn} {$stats->total} Alkohol- und Drogenfahrten in Deutschland – {$date_de}\n\n";
$text .= "{$emoji_bar} Die Zahlen des Tages:\n";
$text .= "{$emoji_beer} {$stats->alkohol} Alkoholfahrten\n";
$text .= "{$emoji_pill} {$stats->drogen} Drogenfahrten\n";
$text .= "{$emoji_car} {$stats->unfaelle} Unfälle\n";
$text .= "🪪 {$stats->fs_entzogen} Führerscheine entzogen\n\n";
if ( $stats->max_bak ) {
$text .= "Höchster Promillewert: " . number_format( (float) $stats->max_bak, 2, ',', '.' ) . " ‰";
if ( $top_bak && $top_bak->stadt ) {
$text .= " ({$top_bak->stadt})";
}
$text .= "\n";
}
if ( $stats->avg_bak ) {
$text .= "Durchschnitt: " . number_format( (float) $stats->avg_bak, 2, ',', '.' ) . " ‰\n";
}
$text .= "\n";
if ( $stats->ai_fazit ) {
$fazit = $stats->ai_fazit;
if ( preg_match( '/\*\*.*?\*\*\s*\n+(.*)/s', $fazit, $fm ) ) {
$fazit = trim( $fm[1] );
}
$fazit = preg_replace( '/\*\*/', '', $fazit );
if ( mb_strlen( $fazit ) > 500 ) {
$fazit = mb_substr( $fazit, 0, 500 );
$last_dot = mb_strrpos( $fazit, '.' );
if ( $last_dot !== false && $last_dot > 200 ) {
$fazit = mb_substr( $fazit, 0, $last_dot + 1 );
} else {
$last_space = mb_strrpos( $fazit, ' ' );
$fazit = mb_substr( $fazit, 0, $last_space ) . ' …';
}
}
$text .= $fazit . "\n\n";
}
$text .= "{$emoji_link} Alle Details & interaktive Karte:\nhttps://www.drogentest-online.de/verkehrsmonitor/\n\n";
$text .= "#Verkehrssicherheit #Alkoholfahrt #Drogenfahrt #Drogentest #Promille #Verkehrsmonitor";
echo "─── FACEBOOK-POST ─────────────────────────────────\n\n";
echo $text;
echo "\n\n────────────────────────────────────────────────────\n";
/* ─── Facebook veröffentlichen ───────────────────────── */
$publish = in_array( '--publish', $argv, true );
if ( $publish ) {
$config_file = dirname( __DIR__ ) . '/.fb-config';
if ( ! file_exists( $config_file ) ) {
fwrite( STDERR, "Fehler: {$config_file} nicht gefunden.\n" );
exit( 1 );
}
$config = array();
foreach ( file( $config_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ) as $line ) {
if ( strpos( $line, '=' ) !== false ) {
list( $k, $v ) = explode( '=', $line, 2 );
$config[ trim( $k ) ] = trim( $v );
}
}
$page_id = $config['PAGE_ID'] ?? '';
$token = $config['ACCESS_TOKEN'] ?? '';
if ( ! $page_id || ! $token ) {
fwrite( STDERR, "Fehler: PAGE_ID oder ACCESS_TOKEN fehlt in .fb-config.\n" );
exit( 1 );
}
$url = "https://graph.facebook.com/v21.0/{$page_id}/photos";
$ch = curl_init();
curl_setopt_array( $ch, array(
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => array(
'source' => new CURLFile( $out_path, 'image/png' ),
'message' => $text,
'access_token' => $token,
),
) );
$response = curl_exec( $ch );
$http = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
curl_close( $ch );
$result = json_decode( $response, true );
if ( $http === 200 && isset( $result['id'] ) ) {
echo "\n✓ Facebook-Post veröffentlicht! ID: {$result['id']}\n";
} else {
$err = $result['error']['message'] ?? $response;
fwrite( STDERR, "\nFehler beim Posten (HTTP {$http}): {$err}\n" );
exit( 1 );
}
} else {
echo "\nHinweis: Mit --publish wird der Post automatisch auf Facebook veröffentlicht.\n";
}
/* ─── Hilfsfunktionen ─────────────────────────────────── */
function strftime_de( $date ) {
$ts = strtotime( $date );
$days = array( 'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag' );
$day = $days[ (int) date( 'w', $ts ) ];
return $day . ', ' . date( 'd.m.Y', $ts );
}
function imagefilledroundedrect( $img, $x1, $y1, $x2, $y2, $r, $color ) {
imagefilledrectangle( $img, $x1 + $r, $y1, $x2 - $r, $y2, $color );
imagefilledrectangle( $img, $x1, $y1 + $r, $x2, $y2 - $r, $color );
imagefilledellipse( $img, $x1 + $r, $y1 + $r, $r * 2, $r * 2, $color );
imagefilledellipse( $img, $x2 - $r, $y1 + $r, $r * 2, $r * 2, $color );
imagefilledellipse( $img, $x1 + $r, $y2 - $r, $r * 2, $r * 2, $color );
imagefilledellipse( $img, $x2 - $r, $y2 - $r, $r * 2, $r * 2, $color );
}
function draw_trend_arrow( $img, $x, $y, $color ) {
imagesetthickness( $img, 2 );
imageline( $img, $x, $y + 6, $x + 14, $y - 6, $color );
imageline( $img, $x + 8, $y - 6, $x + 14, $y - 6, $color );
imageline( $img, $x + 14, $y - 6, $x + 14, $y + 1, $color );
imagesetthickness( $img, 1 );
}
function draw_card_icon( $img, $cx, $cy, $type, $fg ) {
switch ( $type ) {
case 'bottle':
imagefilledrectangle( $img, $cx - 3, $cy - 14, $cx + 1, $cy - 7, $fg );
imagefilledrectangle( $img, $cx - 7, $cy - 7, $cx + 5, $cy + 12, $fg );
imagefilledellipse( $img, $cx - 1, $cy + 12, 12, 4, $fg );
break;
case 'leaf':
imagefilledellipse( $img, $cx, $cy - 3, 18, 22, $fg );
$bg = imagecolorallocatealpha( $img, 42, 157, 100, 0 );
imageline( $img, $cx, $cy - 14, $cx, $cy + 10, $bg );
imageline( $img, $cx - 7, $cy - 5, $cx + 7, $cy + 3, $bg );
imageline( $img, $cx + 7, $cy - 5, $cx - 7, $cy + 3, $bg );
break;
case 'car':
imagefilledrectangle( $img, $cx - 12, $cy - 4, $cx + 12, $cy + 5, $fg );
imagefilledrectangle( $img, $cx - 8, $cy - 10, $cx + 8, $cy - 4, $fg );
imagefilledellipse( $img, $cx - 7, $cy + 7, 7, 7, $fg );
imagefilledellipse( $img, $cx + 7, $cy + 7, 7, 7, $fg );
break;
case 'card':
imagefilledrectangle( $img, $cx - 11, $cy - 8, $cx + 11, $cy + 8, $fg );
$bg = imagecolorallocatealpha( $img, 58, 130, 200, 0 );
imagefilledellipse( $img, $cx - 4, $cy - 2, 7, 7, $bg );
imagefilledrectangle( $img, $cx + 2, $cy - 4, $cx + 9, $cy - 2, $bg );
imagefilledrectangle( $img, $cx + 2, $cy, $cx + 9, $cy + 2, $bg );
imagefilledrectangle( $img, $cx + 2, $cy + 4, $cx + 9, $cy + 6, $bg );
break;
}
}