diff --git a/public/telegram/broadcast_test.php b/public/telegram/broadcast_test.php index d948884..f598640 100644 --- a/public/telegram/broadcast_test.php +++ b/public/telegram/broadcast_test.php @@ -14,7 +14,8 @@ require_once __DIR__ . '/../auth_helpers.php'; $config = require __DIR__ . '/../../config/database.php'; $telegramConfig = require __DIR__ . '/../../config/telegram.php'; -require_once __DIR__ . '/../../config/telegram_message_footer.php'; +require_once __DIR__ . '/../../scripts/telegram/lib/message_footer.php'; +require_once __DIR__ . '/../../scripts/telegram/lib/http.php'; $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', @@ -61,160 +62,6 @@ function textLength(string $value): int return strlen($value); } -function telegramHttpPostJson(string $url, array $payload): array -{ - $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if ($jsonPayload === false) { - return [ - 'ok' => false, - 'status_code' => 0, - 'body' => null, - 'error' => 'Die Telegram-Anfrage konnte nicht als JSON kodiert werden.', - ]; - } - - if (DIRECTORY_SEPARATOR === '\\' && function_exists('shell_exec')) { - $urlBase64 = base64_encode($url); - $payloadBase64 = base64_encode($jsonPayload); - $powerShellScript = str_replace( - ['__URL_BASE64__', '__PAYLOAD_BASE64__'], - [$urlBase64, $payloadBase64], - <<<'PS' -$ErrorActionPreference = 'Stop' -$url = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__URL_BASE64__')) -$body = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__PAYLOAD_BASE64__')) -try { - $response = Invoke-RestMethod -Method Post -Uri $url -ContentType 'application/json' -Body $body - [PSCustomObject]@{ - ok = $true - body = ($response | ConvertTo-Json -Depth 20 -Compress) - error = '' - } | ConvertTo-Json -Compress -} catch { - $stream = $null - $responseBody = '' - if ($_.Exception.Response) { - try { - $stream = $_.Exception.Response.GetResponseStream() - if ($stream) { - $reader = New-Object System.IO.StreamReader($stream) - $responseBody = $reader.ReadToEnd() - } - } catch { - } finally { - if ($stream) { - $stream.Dispose() - } - } - } - [PSCustomObject]@{ - ok = $false - body = $responseBody - error = $_.Exception.Message - } | ConvertTo-Json -Compress -} -PS - ); - $encodedCommandBinary = function_exists('iconv') - ? iconv('UTF-8', 'UTF-16LE', $powerShellScript) - : $powerShellScript; - $encodedCommand = base64_encode($encodedCommandBinary === false ? $powerShellScript : $encodedCommandBinary); - $command = 'powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ' . $encodedCommand; - $rawOutput = shell_exec($command); - - if ($rawOutput !== null && trim($rawOutput) !== '') { - $decodedShell = json_decode(trim($rawOutput), true); - if (is_array($decodedShell)) { - return [ - 'ok' => (bool) ($decodedShell['ok'] ?? false), - 'status_code' => 0, - 'body' => $decodedShell['body'] ?? null, - 'error' => $decodedShell['error'] ?? null, - ]; - } - } - } - - if (function_exists('curl_init')) { - $ch = curl_init($url); - curl_setopt_array($ch, [ - CURLOPT_POST => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ], - CURLOPT_POSTFIELDS => $jsonPayload, - CURLOPT_TIMEOUT => 20, - ]); - - $body = curl_exec($ch); - $curlError = curl_error($ch); - $statusCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE); - curl_close($ch); - - if ($body === false) { - return [ - 'ok' => false, - 'status_code' => $statusCode, - 'body' => null, - 'error' => $curlError !== '' ? $curlError : 'Die Telegram-Anfrage ist fehlgeschlagen.', - ]; - } - - return [ - 'ok' => true, - 'status_code' => $statusCode, - 'body' => $body, - 'error' => null, - ]; - } - - $context = stream_context_create([ - 'http' => [ - 'method' => 'POST', - 'header' => implode("\r\n", [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ]), - 'content' => $jsonPayload, - 'timeout' => 20, - 'ignore_errors' => true, - ], - ]); - - $body = @file_get_contents($url, false, $context); - $statusCode = 0; - $responseHeaders = function_exists('http_get_last_response_headers') - ? http_get_last_response_headers() - : ($http_response_header ?? null); - - if (is_array($responseHeaders)) { - foreach ($responseHeaders as $headerLine) { - if (preg_match('/^HTTP\/\S+\s+(\d{3})\b/', $headerLine, $matches) === 1) { - $statusCode = (int) $matches[1]; - break; - } - } - } - - if ($body === false) { - return [ - 'ok' => false, - 'status_code' => $statusCode, - 'body' => null, - 'error' => 'Die Telegram-Anfrage ist fehlgeschlagen. Auf diesem Server ist moeglicherweise weder cURL noch der HTTPS-Stream-Wrapper verfuegbar.', - ]; - } - - return [ - 'ok' => true, - 'status_code' => $statusCode, - 'body' => $body, - 'error' => null, - ]; -} - function sendTelegramMessage(string $botToken, string $chatId, string $messageText): array { $response = telegramHttpPostJson( diff --git a/public/telegram/webhook.php b/public/telegram/webhook.php index 56a082b..5ae6bf2 100644 --- a/public/telegram/webhook.php +++ b/public/telegram/webhook.php @@ -6,7 +6,8 @@ error_reporting(E_ALL); $config = require __DIR__ . '/../../config/database.php'; $telegramConfig = require __DIR__ . '/../../config/telegram.php'; -require_once __DIR__ . '/../../config/telegram_message_footer.php'; +require_once __DIR__ . '/../../scripts/telegram/lib/message_footer.php'; +require_once __DIR__ . '/../../scripts/telegram/lib/http.php'; $dsn = sprintf( 'mysql:host=%s;dbname=%s;charset=%s', @@ -33,50 +34,6 @@ function telegramWebhookRespond(array $payload, int $statusCode = 200): never exit; } -function telegramHttpPostJson(string $url, array $payload): bool -{ - $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if ($jsonPayload === false) { - return false; - } - - if (function_exists('curl_init')) { - $ch = curl_init($url); - curl_setopt_array($ch, [ - CURLOPT_POST => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ], - CURLOPT_POSTFIELDS => $jsonPayload, - CURLOPT_TIMEOUT => 15, - ]); - - $body = curl_exec($ch); - curl_close($ch); - - return $body !== false; - } - - $context = stream_context_create([ - 'http' => [ - 'method' => 'POST', - 'header' => implode("\r\n", [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ]), - 'content' => $jsonPayload, - 'timeout' => 15, - 'ignore_errors' => true, - ], - ]); - - $body = @file_get_contents($url, false, $context); - - return $body !== false; -} - function telegramSendBotMessage(array $telegramConfig, string $chatId, string $messageText): void { $botToken = trim((string) ($telegramConfig['bot_token'] ?? '')); diff --git a/scripts/telegram/bootstrap.php b/scripts/telegram/bootstrap.php index 6bd169c..1393ba3 100644 --- a/scripts/telegram/bootstrap.php +++ b/scripts/telegram/bootstrap.php @@ -17,7 +17,7 @@ $rootDir = dirname(__DIR__, 2); $stateFile = __DIR__ . DIRECTORY_SEPARATOR . 'telegram_cron_state.json'; $dbConfig = require $rootDir . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'database.php'; $telegramConfig = require $rootDir . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'telegram.php'; -require_once $rootDir . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'telegram_message_footer.php'; +require_once __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'message_footer.php'; $GLOBALS['filterColorConfigPath'] = $rootDir . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'filter_colors.json'; diff --git a/scripts/telegram/lib/http.php b/scripts/telegram/lib/http.php new file mode 100644 index 0000000..abfc8d7 --- /dev/null +++ b/scripts/telegram/lib/http.php @@ -0,0 +1,155 @@ + false, + 'status_code' => 0, + 'body' => null, + 'error' => 'Die Telegram-Anfrage konnte nicht als JSON kodiert werden.', + ]; + } + + if (DIRECTORY_SEPARATOR === '\\' && function_exists('shell_exec')) { + $urlBase64 = base64_encode($url); + $payloadBase64 = base64_encode($jsonPayload); + $powerShellScript = str_replace( + ['__URL_BASE64__', '__PAYLOAD_BASE64__'], + [$urlBase64, $payloadBase64], + <<<'PS' +$ErrorActionPreference = 'Stop' +$url = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__URL_BASE64__')) +$body = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__PAYLOAD_BASE64__')) +try { + $response = Invoke-RestMethod -Method Post -Uri $url -ContentType 'application/json' -Body $body + [PSCustomObject]@{ + ok = $true + body = ($response | ConvertTo-Json -Depth 20 -Compress) + error = '' + } | ConvertTo-Json -Compress +} catch { + $stream = $null + $responseBody = '' + if ($_.Exception.Response) { + try { + $stream = $_.Exception.Response.GetResponseStream() + if ($stream) { + $reader = New-Object System.IO.StreamReader($stream) + $responseBody = $reader.ReadToEnd() + } + } catch { + } finally { + if ($stream) { + $stream.Dispose() + } + } + } + [PSCustomObject]@{ + ok = $false + body = $responseBody + error = $_.Exception.Message + } | ConvertTo-Json -Compress +} +PS + ); + $encodedCommandBinary = function_exists('iconv') + ? iconv('UTF-8', 'UTF-16LE', $powerShellScript) + : $powerShellScript; + $encodedCommand = base64_encode($encodedCommandBinary === false ? $powerShellScript : $encodedCommandBinary); + $command = 'powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ' . $encodedCommand; + $rawOutput = shell_exec($command); + + if ($rawOutput !== null && trim($rawOutput) !== '') { + $decodedShell = json_decode(trim($rawOutput), true); + if (is_array($decodedShell)) { + return [ + 'ok' => (bool) ($decodedShell['ok'] ?? false), + 'status_code' => 0, + 'body' => $decodedShell['body'] ?? null, + 'error' => $decodedShell['error'] ?? null, + ]; + } + } + } + + if (function_exists('curl_init')) { + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($jsonPayload), + ], + CURLOPT_POSTFIELDS => $jsonPayload, + CURLOPT_TIMEOUT => 20, + ]); + + $body = curl_exec($ch); + $curlError = curl_error($ch); + $statusCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE); + + if ($body === false) { + return [ + 'ok' => false, + 'status_code' => $statusCode, + 'body' => null, + 'error' => $curlError !== '' ? $curlError : 'Die Telegram-Anfrage ist fehlgeschlagen.', + ]; + } + + return [ + 'ok' => true, + 'status_code' => $statusCode, + 'body' => $body, + 'error' => null, + ]; + } + + $context = stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => implode("\r\n", [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($jsonPayload), + ]), + 'content' => $jsonPayload, + 'timeout' => 20, + 'ignore_errors' => true, + ], + ]); + + $body = @file_get_contents($url, false, $context); + $statusCode = 0; + $responseHeaders = function_exists('http_get_last_response_headers') + ? http_get_last_response_headers() + : ($http_response_header ?? null); + + if (is_array($responseHeaders)) { + foreach ($responseHeaders as $headerLine) { + if (preg_match('/^HTTP\/\S+\s+(\d{3})\b/', $headerLine, $matches) === 1) { + $statusCode = (int) $matches[1]; + break; + } + } + } + + if ($body === false) { + return [ + 'ok' => false, + 'status_code' => $statusCode, + 'body' => null, + 'error' => 'Die Telegram-Anfrage ist fehlgeschlagen. Auf diesem Server ist moeglicherweise weder cURL noch der HTTPS-Stream-Wrapper verfuegbar.', + ]; + } + + return [ + 'ok' => true, + 'status_code' => $statusCode, + 'body' => $body, + 'error' => null, + ]; +} diff --git a/config/telegram_message_footer.php b/scripts/telegram/lib/message_footer.php similarity index 100% rename from config/telegram_message_footer.php rename to scripts/telegram/lib/message_footer.php diff --git a/scripts/telegram/lib/telegram_api.php b/scripts/telegram/lib/telegram_api.php index 877446b..6160254 100644 --- a/scripts/telegram/lib/telegram_api.php +++ b/scripts/telegram/lib/telegram_api.php @@ -9,123 +9,7 @@ declare(strict_types=1); * und Dokumenten. Die Cron-Tasks muessen dadurch keine Request-Details kennen. */ -function telegramHttpPostJson(string $url, array $payload): array -{ - $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if ($jsonPayload === false) { - return [ - 'ok' => false, - 'error' => 'Die Telegram-Anfrage konnte nicht als JSON kodiert werden.', - 'body' => null, - ]; - } - - if (DIRECTORY_SEPARATOR === '\\' && function_exists('shell_exec')) { - $urlBase64 = base64_encode($url); - $payloadBase64 = base64_encode($jsonPayload); - $powerShellScript = str_replace( - ['__URL_BASE64__', '__PAYLOAD_BASE64__'], - [$urlBase64, $payloadBase64], - <<<'PS' -$ErrorActionPreference = 'Stop' -$url = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__URL_BASE64__')) -$body = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('__PAYLOAD_BASE64__')) -try { - $response = Invoke-RestMethod -Method Post -Uri $url -ContentType 'application/json' -Body $body - [PSCustomObject]@{ - ok = $true - body = ($response | ConvertTo-Json -Depth 20 -Compress) - error = '' - } | ConvertTo-Json -Compress -} catch { - $stream = $null - $responseBody = '' - if ($_.Exception.Response) { - try { - $stream = $_.Exception.Response.GetResponseStream() - if ($stream) { - $reader = New-Object System.IO.StreamReader($stream) - $responseBody = $reader.ReadToEnd() - } - } catch { - } finally { - if ($stream) { - $stream.Dispose() - } - } - } - [PSCustomObject]@{ - ok = $false - body = $responseBody - error = $_.Exception.Message - } | ConvertTo-Json -Compress -} -PS - ); - $encodedCommandBinary = function_exists('iconv') - ? iconv('UTF-8', 'UTF-16LE', $powerShellScript) - : $powerShellScript; - $encodedCommand = base64_encode($encodedCommandBinary === false ? $powerShellScript : $encodedCommandBinary); - $command = 'powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ' . $encodedCommand; - $rawOutput = shell_exec($command); - - if ($rawOutput !== null && trim($rawOutput) !== '') { - $decodedShell = json_decode(trim($rawOutput), true); - if (is_array($decodedShell)) { - return [ - 'ok' => (bool) ($decodedShell['ok'] ?? false), - 'error' => $decodedShell['error'] ?? null, - 'body' => $decodedShell['body'] ?? null, - ]; - } - } - } - - if (function_exists('curl_init')) { - $ch = curl_init($url); - curl_setopt_array($ch, [ - CURLOPT_POST => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ], - CURLOPT_POSTFIELDS => $jsonPayload, - CURLOPT_TIMEOUT => 20, - ]); - - $body = curl_exec($ch); - $error = curl_error($ch); - curl_close($ch); - - return [ - 'ok' => $body !== false, - 'error' => $body === false ? $error : null, - 'body' => $body !== false ? $body : null, - ]; - } - - $context = stream_context_create([ - 'http' => [ - 'method' => 'POST', - 'header' => implode("\r\n", [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($jsonPayload), - ]), - 'content' => $jsonPayload, - 'timeout' => 20, - 'ignore_errors' => true, - ], - ]); - - $body = @file_get_contents($url, false, $context); - - return [ - 'ok' => $body !== false, - 'error' => $body === false ? 'HTTP-Request fehlgeschlagen.' : null, - 'body' => $body !== false ? $body : null, - ]; -} +require_once __DIR__ . '/http.php'; function telegramHttpPostMultipart(string $url, array $fields, string $fileField, string $filePath, ?string $fileName = null): array @@ -217,7 +101,6 @@ PS $body = curl_exec($ch); $error = curl_error($ch); - curl_close($ch); return [ 'ok' => $body !== false,