Compare commits
37 Commits
stable/1.3
...
923dafecc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
923dafecc9 | ||
|
|
cd031464e6 | ||
|
|
a093603c3c | ||
|
|
81c28b4a3b | ||
|
|
93ae2cdaa9 | ||
|
|
97c21a4894 | ||
|
|
560ef6589c | ||
|
|
e4a21f4d7c | ||
|
|
c2e488c8e7 | ||
|
|
59b5ffc82f | ||
|
|
2913f3f032 | ||
| 67a39afe0f | |||
|
|
49ad1f2438 | ||
|
|
7a596597da | ||
|
|
0b7d47e816 | ||
|
|
6e7fd28762 | ||
|
|
756827d92b | ||
|
|
3f2c5c1e73 | ||
|
|
79e27ee95a | ||
|
|
af3d7d33a1 | ||
|
|
4636e50b25 | ||
|
|
88f87e15b4 | ||
|
|
e44c10c5c2 | ||
|
|
48bd8e66f2 | ||
|
|
2e5b29bd9d | ||
|
|
b689d73065 | ||
|
|
ff40210fb6 | ||
|
|
209bb0b00c | ||
|
|
6bec287363 | ||
|
|
b035d8c2d9 | ||
|
|
17ced6d294 | ||
|
|
4b54e14522 | ||
|
|
f1b4aaf23a | ||
|
|
e6fd1de954 | ||
|
|
c631b51ba2 | ||
|
|
3e083b4eb9 | ||
|
|
0c41265fb6 |
99
NEXT_STEPS.md
Normal file
99
NEXT_STEPS.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# Next Steps
|
||||||
|
|
||||||
|
- #TODO Unified error strategy (Definition)
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `quality`, `api`
|
||||||
|
- Ziel: Einheitliches Verhalten bei Fehlern.
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- ADR/kurze Doku: wann `null/false`, wann Exception.
|
||||||
|
- `sql.php`, `link-meta.php`, `troy-api.php` folgen derselben Strategie.
|
||||||
|
- Mindestens 3 Beispiele in `README.md` dokumentiert.
|
||||||
|
- Festlegung:
|
||||||
|
- Exceptions fuer interne/unerwartete Fehler (Konfiguration fehlt, DB/HTTP/JSON-Fehler, Parsing-Fehler, invalide Argumente).
|
||||||
|
- `null` nur fuer "kein Ergebnis" als erwarteter Zustand (z. B. URL ohne OG-Metadaten).
|
||||||
|
- `false` nur fuer boolesche Checks/Operationen mit reinem Erfolg-Flag; keine Detailfehler ueber `false`.
|
||||||
|
- Keine Mischung pro Funktion: jede Funktion dokumentiert exakt einen Fehlerkanal in PHPDoc/README.
|
||||||
|
- Alle gecatchten Exceptions werden mit Kontext weitergeworfen (ohne Secrets), nicht still geschluckt.
|
||||||
|
|
||||||
|
- #TODO Complete `secret.php.example`
|
||||||
|
- Aufwand: `S`
|
||||||
|
- Labels: `docs`, `config`
|
||||||
|
- Ziel: Vollstaendige Vorlagedatei fuer lokale Setups.
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Alle erwarteten Variablen aus `sql.php`, `mail.php`, `troy-api.php` enthalten.
|
||||||
|
- Jede Variable hat kurzen Kommentar.
|
||||||
|
- Dateiformat entspricht direkt nutzbarer Vorlage.
|
||||||
|
|
||||||
|
- #TODO Remove `@` error suppression incrementally
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `quality`, `safety`
|
||||||
|
- Ziel: Fehler sichtbar und kontrolliert behandeln.
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Alle `@`-Operatoren inventarisiert.
|
||||||
|
- Ersetzungen mit explizitem Error-Handling umgesetzt.
|
||||||
|
- Keine neue `@`-Verwendung in geaenderten Dateien.
|
||||||
|
|
||||||
|
- #TODO Sicherheit und Robustheit
|
||||||
|
|
||||||
|
- #TODO Harden URL fetching against SSRF
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `security`, `network`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Private/loopback ranges werden blockiert.
|
||||||
|
- Optionales Host-Allowlist-Feature vorhanden.
|
||||||
|
- Tests fuer geblockte und erlaubte Ziele vorhanden.
|
||||||
|
|
||||||
|
- #TODO Centralize HTTP limits (timeout/redirect/size)
|
||||||
|
- Aufwand: `S`
|
||||||
|
- Labels: `robustness`, `network`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Eine zentrale Konfiguration fuer HTTP-Limits.
|
||||||
|
- `og.php` und `link-meta.php` nutzen dieselben Limits.
|
||||||
|
- Default-Werte sind in README dokumentiert.
|
||||||
|
|
||||||
|
- #TODO Improve SQL error handling + logging
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `sql`, `robustness`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- `prepare()`/`execute()`-Fehler werden explizit behandelt.
|
||||||
|
- Fehler enthalten Query-Kontext ohne Secrets.
|
||||||
|
- Verhalten entspricht der definierten Error-Strategie.
|
||||||
|
|
||||||
|
- #TODO Replace fragile HTML allowlist sanitizer
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `security`, `string`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- `onlySimpleHTML()` wird durch robusteren Ansatz ersetzt.
|
||||||
|
- Erlaubte Tags sind konfigurierbar dokumentiert.
|
||||||
|
- Regression-Tests fuer typische Eingaben vorhanden.
|
||||||
|
|
||||||
|
- #TODO Code-Qualitaet
|
||||||
|
|
||||||
|
- Sammel-Issue: Naming-Konvention, SQL-Binding-Refactor, Legacy-Markierung, Markdown-Konsolidierung, klare Modulgrenzen.
|
||||||
|
- Aufwand: `L`
|
||||||
|
- Empfehlung: in 3-5 Unter-Issues aufteilen.
|
||||||
|
|
||||||
|
- #TODO Tests und Tooling
|
||||||
|
|
||||||
|
- #TODO Bootstrap test/tooling baseline
|
||||||
|
- Aufwand: `M`
|
||||||
|
- Labels: `testing`, `ci`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- PHPUnit laeuft lokal mit ersten Smoke-Tests.
|
||||||
|
- PHPStan/Psalm auf niedriger Stufe integriert.
|
||||||
|
- CI fuehrt mindestens Lint + Tests bei Push aus.
|
||||||
|
|
||||||
|
- #TODO Prepare Composer + namespace migration path
|
||||||
|
- Aufwand: `L`
|
||||||
|
- Labels: `architecture`
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Vorschlag fuer Zielstruktur (`src/`, namespaces, autoload).
|
||||||
|
- Migrationsplan fuer prozedurale Helfer zu Klassen.
|
||||||
|
- Konfigurationsobjekt und HTTP-Adapter als Zielbild beschrieben.
|
||||||
|
|
||||||
|
## Empfohlene Reihenfolge
|
||||||
|
|
||||||
|
1. `#1` bis `#5` (kurzfristig, hoher Hebel)
|
||||||
|
2. `#6` bis `#10` (Sicherheit/Robustheit)
|
||||||
|
3. `#11` (Tests + CI als Guardrail)
|
||||||
|
4. `#12` und Sammel-Issue aus Abschnitt 3
|
||||||
185
README.md
185
README.md
@@ -1,2 +1,187 @@
|
|||||||
# php-func-lib
|
# php-func-lib
|
||||||
|
|
||||||
|
Kleine PHP-Utility-Bibliothek mit wiederverwendbaren Helfern fuer:
|
||||||
|
|
||||||
|
- Strings und einfache Sanitization
|
||||||
|
- Zahlenformatierung
|
||||||
|
- SQL-Zugriffe (mysqli + prepared statements)
|
||||||
|
- Mailversand
|
||||||
|
- Link/OpenGraph-Metadaten
|
||||||
|
- Debug-Helfer
|
||||||
|
- Troy-/Gitea-API-Aufrufe
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Als Git-Submodule in ein Projekt einbinden:
|
||||||
|
|
||||||
|
```bash
|
||||||
git submodule add https://git.seemsleg.it/pub/php-func-lib lib
|
git submodule add https://git.seemsleg.it/pub/php-func-lib lib
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach je nach Bedarf einzelne Dateien einbinden oder zentral ueber `_func.php` laden.
|
||||||
|
|
||||||
|
## Schnellstart
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/_func.php';
|
||||||
|
|
||||||
|
echo shortener("Ein sehr langer Text", 10); // "Ein sehr..."
|
||||||
|
echo decade(12345); // "12.345 K" (je nach PHP-Konvertierung)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module
|
||||||
|
|
||||||
|
- `string.php`: String-Helfer (`shortener`, `onlyAlpha`, `startsWith`, `endsWith`, `linkify`, ...)
|
||||||
|
- `numbers.php`: Zahlen-Helfer (`decade`, `onlyNumeric`)
|
||||||
|
- `sql.php`: Klasse `SQL` fuer Datenbankzugriffe (`get`, `single`, `list`, `keyval`, `set`)
|
||||||
|
- `mail.php`: Mailfunktionen (`send_mail`, `send_html_mail`, `send_php_mail`)
|
||||||
|
- `link-meta.php`: URL-Validierung, Fetching, Meta-Parsing, Bilddownload, Tag-Sanitization
|
||||||
|
- `og.php`: Einfacher OG-Scan (`scanOG`)
|
||||||
|
- `troy-api.php`: API-Helfer fuer Troy/Gitea (`sendToTroy`, `sendToGitea`)
|
||||||
|
- `debug.php`: Cookie-basierte Debug-Ausgabe
|
||||||
|
- `markdown.php`: einfache Markdown-nahe Formatierung (`md`)
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Einige Module erwarten ein lokales `secret.php` (siehe `secret.php.example`).
|
||||||
|
Folgende Felder werden verwendet:
|
||||||
|
|
||||||
|
- `$_m['host']`, `$_m['user']`, `$_m['pass']`, `$_m['data']`, `$_m['pre']`, `$_m['salt']` fuer `sql.php`
|
||||||
|
- `$_sendermail`, optional `$_smtp['srv']`, `$_smtp['user']`, `$_smtp['pw']` fuer `mail.php`
|
||||||
|
- `$giteaUrl`, `$giteaOwner`, `$giteaRepo`, `$giteaToken` fuer `troy-api.php`
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
// secret.php im selben Verzeichnis wie die Bibliothek ablegen
|
||||||
|
if (!defined('SQL_LOG')) define('SQL_LOG', 0);
|
||||||
|
$giteaUrl = 'https://git.example.org';
|
||||||
|
$giteaOwner = 'org';
|
||||||
|
$giteaRepo = 'repo';
|
||||||
|
$giteaToken = 'token';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Runnable Examples
|
||||||
|
|
||||||
|
### `string.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/string.php';
|
||||||
|
|
||||||
|
echo shortener('Ein sehr langer Text', 12) . PHP_EOL;
|
||||||
|
echo onlyAlpha('Hi! #42?') . PHP_EOL;
|
||||||
|
echo linkify('Mehr Infos: https://example.org') . PHP_EOL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `numbers.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/numbers.php';
|
||||||
|
|
||||||
|
echo decade(15320) . PHP_EOL;
|
||||||
|
echo onlyNumeric('EUR -12.50') . PHP_EOL;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `sql.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
if (!defined('SQL_LOG')) define('SQL_LOG', 0);
|
||||||
|
include_once __DIR__ . '/sql.php';
|
||||||
|
|
||||||
|
$sql = new SQL();
|
||||||
|
$row = $sql->single('SELECT 1 AS ok');
|
||||||
|
var_export($row);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `mail.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/mail.php';
|
||||||
|
|
||||||
|
send_mail('user@example.org', 'Test', 'Hallo Welt', 'ok', 'error');
|
||||||
|
```
|
||||||
|
|
||||||
|
### `link-meta.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/string.php';
|
||||||
|
include_once __DIR__ . '/link-meta.php';
|
||||||
|
|
||||||
|
$info = getPageInfo('https://example.org');
|
||||||
|
if ($info['ok']) {
|
||||||
|
echo $info['title'] . PHP_EOL;
|
||||||
|
echo $info['description'] . PHP_EOL;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `og.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/og.php';
|
||||||
|
|
||||||
|
$og = scanOG('https://example.org');
|
||||||
|
print_r($og);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `troy-api.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/troy-api.php';
|
||||||
|
|
||||||
|
$res = sendToTroy(['msg' => 'hello']);
|
||||||
|
var_dump($res);
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/troy-api.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$issue = sendToGitea('Test issue', 'Automatisch erstellt.');
|
||||||
|
print_r($issue);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `debug.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/debug.php';
|
||||||
|
|
||||||
|
debugCookie(true);
|
||||||
|
debug(['foo' => 'bar']);
|
||||||
|
```
|
||||||
|
|
||||||
|
### `markdown.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
include_once __DIR__ . '/string.php';
|
||||||
|
include_once __DIR__ . '/markdown.php';
|
||||||
|
|
||||||
|
echo md("! Titel\n\n* Punkt A\n* Punkt B");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
- Kein Composer/Autoload; Includes muessen manuell gesetzt werden.
|
||||||
|
- `sql.php` erwartet `secret.php` im Bibliotheksverzeichnis und nutzt `mysqli`.
|
||||||
|
- Netzwerkfunktionen (`link-meta.php`, `og.php`, `troy-api.php`) nutzen `file_get_contents` und haben keine SSRF-Allowlist.
|
||||||
|
- Mehrere Funktionen sind historisch gewachsen und nutzen teils inkonsistentes Error-Handling (`false`, `null`, Exceptions).
|
||||||
|
- `markdown.php` und `onlySimpleHTML()` sind einfache Parser/Sanitizer, nicht vollstaendige Markdown- oder HTML-Sicherheitsloesungen.
|
||||||
|
|
||||||
|
## Hinweise
|
||||||
|
|
||||||
|
- Die Bibliothek ist bewusst leichtgewichtig und ohne Composer-Setup gehalten.
|
||||||
|
- Fuer geplante Verbesserungen siehe `NEXT_STEPS.md`.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
// include ('config.php');
|
// include ('config.php');
|
||||||
include_once ('sql.php');
|
include_once ('sql.php');
|
||||||
$sql = new SQL ();
|
$sql = new SQL ();
|
||||||
@@ -6,5 +7,6 @@ include_once ('string.php');
|
|||||||
include_once ('numbers.php');
|
include_once ('numbers.php');
|
||||||
include_once ('mail.php');
|
include_once ('mail.php');
|
||||||
include_once ('debug.php');
|
include_once ('debug.php');
|
||||||
|
include_once ('troy-api.php');
|
||||||
// include_once ('markdown.php');
|
// include_once ('markdown.php');
|
||||||
?>
|
?>
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
function debug($s) {
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function debug(mixed $s): void {
|
||||||
if(isset($_COOKIE['debug']))
|
if(isset($_COOKIE['debug']))
|
||||||
print_r($s);
|
print_r($s);
|
||||||
}
|
}
|
||||||
|
|
||||||
function debugCookie($on=true) {
|
function debugCookie(bool $on = true): void {
|
||||||
if($on) {
|
if($on) {
|
||||||
setcookie('debug','1',time()+(60*60*24*365),"/");
|
setcookie('debug','1',time()+(60*60*24*365),"/");
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -1,21 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
$_ips_crawler = array (
|
$_ips_crawler = array (
|
||||||
|
'34.79.234.76', // google
|
||||||
'40.77.167.', // bing bot
|
'40.77.167.', // bing bot
|
||||||
|
'54.36.148.', // ahrefbot
|
||||||
|
'54.36.149.', // ahrefbot
|
||||||
'66.249.',
|
'66.249.',
|
||||||
'62.138.',
|
'62.138.',
|
||||||
'62.210.149.60',
|
'62.210.149.60',
|
||||||
|
'65.21.180.26', // seekport
|
||||||
|
'81.209.177.145', // website-datenbank.de
|
||||||
|
'85.25.177.', // abuse
|
||||||
|
'85.25.210.', // hosteurope abuse
|
||||||
'92.118.160.37', // netsystem research bot
|
'92.118.160.37', // netsystem research bot
|
||||||
'104.155.85.', // google
|
'104.155.85.', // google
|
||||||
'114.119.1', // petalbot
|
'114.119.1', // petalbot
|
||||||
|
'144.76.15.153', // mj12bot
|
||||||
|
'148.251.120.201', // mj12bot
|
||||||
|
'157.55.39.', // microsoft???
|
||||||
|
'172.217.', //google
|
||||||
|
'176.125.230.38', //sql inj
|
||||||
'185.191.171.', // semrush bot
|
'185.191.171.', // semrush bot
|
||||||
'207.46.13.', // bing bot
|
|
||||||
'54.36.148.', // ahrefbot
|
|
||||||
'54.36.149.', // ahrefbot
|
|
||||||
'216.244.66.196', // opensiteexplorer
|
|
||||||
'65.21.180.26', // seekport
|
|
||||||
'81.209.177.145', // website-datenbank.de
|
|
||||||
'2a01:4f8:190:4244::2', // mj12bot
|
|
||||||
'192.99.5.225', // ...
|
'192.99.5.225', // ...
|
||||||
'157.55.39.' // microsoft???
|
'205.185.115.87', //sex spam
|
||||||
|
'207.46.13.', // bing bot
|
||||||
|
'216.58.', //google
|
||||||
|
'216.244.66.196', // opensiteexplorer
|
||||||
|
'2a01:4f8:190:4244::2', // mj12bot
|
||||||
|
'2a01:4f8:162:43c5::2', // mj12bot
|
||||||
);
|
);
|
||||||
|
function checkHuman(): bool {
|
||||||
|
global $_ips_crawler;
|
||||||
|
if (stripos ( $_SERVER ['HTTP_USER_AGENT'], 'bot' ) !== false || stripos ( $_SERVER ['HTTP_USER_AGENT'], 'crawler' ) !== false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ( $_ips_crawler as $np ) {
|
||||||
|
if (startsWith ( $_SERVER ['REMOTE_ADDR'], $np )) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
180
link-meta.php
Normal file
180
link-meta.php
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function httpContext(int $timeout = 8) {
|
||||||
|
return stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'timeout' => $timeout,
|
||||||
|
'follow_location' => 1,
|
||||||
|
'max_redirects' => 4,
|
||||||
|
'user_agent' => 'star-citizen.de-linkbot/1.0',
|
||||||
|
'ignore_errors' => true
|
||||||
|
],
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer' => true,
|
||||||
|
'verify_peer_name' => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeUrl(string $url): ?string {
|
||||||
|
$url = trim($url);
|
||||||
|
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = parse_url($url);
|
||||||
|
if (!$parts || !isset($parts['scheme'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scheme = strtolower($parts['scheme']);
|
||||||
|
if ($scheme !== 'http' && $scheme !== 'https') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveUrl(string $url, string $baseUrl): ?string {
|
||||||
|
$url = trim($url);
|
||||||
|
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$baseParts = parse_url($baseUrl);
|
||||||
|
if (!$baseParts || !isset($baseParts['scheme']) || !isset($baseParts['host'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strpos($url, '//') === 0) {
|
||||||
|
return $baseParts['scheme'] . ':' . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = '/';
|
||||||
|
if (!empty($baseParts['path'])) {
|
||||||
|
$path = preg_replace('#/[^/]*$#', '/', $baseParts['path']);
|
||||||
|
if ($path === null || $path === '') {
|
||||||
|
$path = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($url) && $url[0] === '/') {
|
||||||
|
return $baseParts['scheme'] . '://' . $baseParts['host'] . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $baseParts['scheme'] . '://' . $baseParts['host'] . $path . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeFetch(string $url, int $timeout = 8): ?string {
|
||||||
|
$ctx = httpContext($timeout);
|
||||||
|
$content = @file_get_contents($url, false, $ctx);
|
||||||
|
return $content === false ? null : $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadImageFromUrl(string $url, string $baseUrl, string $destinationFolder = 'upl/'): ?string {
|
||||||
|
$resolved = resolveUrl($url, $baseUrl);
|
||||||
|
if ($resolved === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/\.(jpg|jpeg|png|gif|bmp|webp)(?:\?|#|$)/i', $resolved)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$imageContent = safeFetch($resolved, 10);
|
||||||
|
if ($imageContent === null || strlen($imageContent) === 0 || strlen($imageContent) > (5 * 1024 * 1024)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = parse_url($resolved, PHP_URL_PATH) ?? '';
|
||||||
|
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||||||
|
if ($ext === '' || !preg_match('/^(jpg|jpeg|png|gif|bmp|webp)$/', $ext)) {
|
||||||
|
$ext = 'png';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dir($destinationFolder)) {
|
||||||
|
@mkdir($destinationFolder, 0775, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$md5Hash = md5($imageContent);
|
||||||
|
$filePath = rtrim($destinationFolder, '/\\') . '/' . $md5Hash . '.' . $ext;
|
||||||
|
$written = @file_put_contents($filePath, $imageContent);
|
||||||
|
if ($written === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseMetaContent(string $html, string $attr, string $name): ?string {
|
||||||
|
$pattern = '/<meta[^>]*' . $attr . '=["\']' . preg_quote($name, '/') . '["\'][^>]*content=["\']([^"\']+)["\'][^>]*>/i';
|
||||||
|
if (preg_match($pattern, $html, $matches) && isset($matches[1])) {
|
||||||
|
return trim(html_entity_decode($matches[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPageInfo(string $url): array {
|
||||||
|
$ret = [
|
||||||
|
'ok' => false,
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
|
'logo' => null,
|
||||||
|
'error' => null
|
||||||
|
];
|
||||||
|
|
||||||
|
$normalized = normalizeUrl($url);
|
||||||
|
if ($normalized === null) {
|
||||||
|
$ret['error'] = 'ungueltige_url';
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = safeFetch($normalized, 10);
|
||||||
|
if ($html === null) {
|
||||||
|
$ret['error'] = 'seite_nicht_erreichbar';
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = parseMetaContent($html, 'property', 'og:title') ?? parseMetaContent($html, 'name', 'title');
|
||||||
|
$description = parseMetaContent($html, 'property', 'og:description') ?? parseMetaContent($html, 'name', 'description');
|
||||||
|
$image = parseMetaContent($html, 'property', 'og:image') ?? parseMetaContent($html, 'name', 'image');
|
||||||
|
|
||||||
|
if ($title === null && preg_match('/<title>\s*(.*?)\s*<\/title>/is', $html, $matchTitle)) {
|
||||||
|
$title = trim(html_entity_decode($matchTitle[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$logo = null;
|
||||||
|
if ($image !== null && $image !== '') {
|
||||||
|
$img = downloadImageFromUrl($image, $normalized);
|
||||||
|
if ($img !== null) {
|
||||||
|
$logo = '/' . ltrim($img, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret['ok'] = true;
|
||||||
|
$ret['title'] = $title ?? '';
|
||||||
|
$ret['description'] = $description ?? '';
|
||||||
|
$ret['logo'] = $logo;
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeTags(array $input): array {
|
||||||
|
$ret = [];
|
||||||
|
foreach ($input as $tag) {
|
||||||
|
if (!is_string($tag)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$clean = onlyAlpha(trim($tag), '_\-');
|
||||||
|
if ($clean === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$clean = ucfirst(substr($clean, 0, 35));
|
||||||
|
$ret[$clean] = true;
|
||||||
|
if (count($ret) >= 20) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array_keys($ret);
|
||||||
|
}
|
||||||
|
|
||||||
90
mail.php
90
mail.php
@@ -1,10 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
function send_mail($an, $betreff, $text, $ok = '', $error = '') {
|
declare(strict_types=1);
|
||||||
include 'secret.php';
|
|
||||||
|
function mail_contains_header_injection(string $value): bool {
|
||||||
|
return strpbrk($value, "\r\n\0") !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mail_is_valid_email(string $value): bool {
|
||||||
|
if (mail_contains_header_injection($value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_mail(string $an, string $betreff, string $text, string $ok = '', string $error = ''): void {
|
||||||
|
global $absender;
|
||||||
$sender = 'noreply@troy-grunt.de';
|
$sender = 'noreply@troy-grunt.de';
|
||||||
|
if(isset($absender) && $absender) {
|
||||||
|
$sender = $absender;
|
||||||
|
}else{
|
||||||
|
include 'secret.php';
|
||||||
if (isset ( $_sendermail )) {
|
if (isset ( $_sendermail )) {
|
||||||
$sender = $_sendermail;
|
$sender = $_sendermail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!mail_is_valid_email($an) || !mail_is_valid_email($sender) || mail_contains_header_injection($betreff)) {
|
||||||
|
echo $error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
$header = 'From: ' . $sender . "\r\n";
|
$header = 'From: ' . $sender . "\r\n";
|
||||||
$header .= 'To: ' . $an . "\r\n";
|
$header .= 'To: ' . $an . "\r\n";
|
||||||
$header .= 'Content-Type:text/html' . "\r\n";
|
$header .= 'Content-Type:text/html' . "\r\n";
|
||||||
@@ -18,3 +40,67 @@ function send_mail($an, $betreff, $text, $ok = '', $error = '') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function send_html_mail(string $an, string $betreff, string $text, string $ok = '', string $error = ''): void {
|
||||||
|
global $absender;
|
||||||
|
$sender = 'noreply@troy-grunt.de';
|
||||||
|
if(isset($absender) && $absender) {
|
||||||
|
$sender = $absender;
|
||||||
|
}else{
|
||||||
|
include 'secret.php';
|
||||||
|
if (isset ( $_sendermail )) {
|
||||||
|
$sender = $_sendermail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mail_is_valid_email($an) || !mail_is_valid_email($sender) || mail_contains_header_injection($betreff)) {
|
||||||
|
echo $error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$boundary = md5($an.$betreff.$text.time());
|
||||||
|
|
||||||
|
$header = 'From: ' . $sender . "\n";
|
||||||
|
$header .= 'To: ' . $an . "\n";
|
||||||
|
$header .= 'Content-Type:multipart/alternative;boundary='.$boundary . "\n";
|
||||||
|
$header .= 'X-Mailer: PHP/' . phpversion ();
|
||||||
|
$content = "This is multipart message using MIME\n";
|
||||||
|
$content .= "--" . $boundary . "\n";
|
||||||
|
$content .= "Content-type: text/plain;charset=utf-8\n";
|
||||||
|
$content .= 'Content-Transfer-Encoding: 8bit' . "\n\n";
|
||||||
|
$content .= strip_tags($text)."\n\n";
|
||||||
|
$content .= "--" . $boundary . "\n";
|
||||||
|
$content .= "Content-type: text/html;charset=utf-8\n";
|
||||||
|
$content .= "Content-Transfer-Encoding: 8bit". "\n\n";
|
||||||
|
$content .= '<html><body>'.$text.'</body></html>'."\n\n";
|
||||||
|
|
||||||
|
if (mail ( $an, $betreff, $content, $header ) === true) {
|
||||||
|
echo $ok;
|
||||||
|
} else {
|
||||||
|
echo $error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_php_mail(string $an, string $betreff, string $text, string $ok = '', string $error = ''): void {
|
||||||
|
global $_sendermail;
|
||||||
|
$sender = 'noreply@troy-grunt.de';
|
||||||
|
if (isset ( $_sendermail )) {
|
||||||
|
$sender = $_sendermail;
|
||||||
|
}
|
||||||
|
if (!mail_is_valid_email($an) || !mail_is_valid_email($sender) || mail_contains_header_injection($betreff)) {
|
||||||
|
echo $error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
include 'php-mailer/PHPMailer.php';
|
||||||
|
$mail = new PHPMailer();
|
||||||
|
|
||||||
|
$mail->setFrom($sender);
|
||||||
|
$mail->addAddress($an);
|
||||||
|
$mail->Subject = $betreff;
|
||||||
|
$mail->msgHTML($text, __DIR__);
|
||||||
|
$mail->AltBody = strip_tags($text);
|
||||||
|
|
||||||
|
if (!$mail->send()) {
|
||||||
|
echo 'Mailer Error: ' . $mail->ErrorInfo;
|
||||||
|
} else {
|
||||||
|
echo 'Message sent!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
// TODO markdown imple
|
// TODO markdown imple
|
||||||
function md($str) {
|
function md(string $str): string {
|
||||||
// return nl2br ( $str ); // TODO md problem
|
// return nl2br ( $str ); // TODO md problem
|
||||||
$text = '<p>';
|
$text = '<p>';
|
||||||
$lv = 0;
|
$lv = 0;
|
||||||
@@ -75,7 +76,7 @@ function md($str) {
|
|||||||
$text .= '</p>';
|
$text .= '</p>';
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
function _md_link_replacer($in) {
|
function _md_link_replacer(array $in): string {
|
||||||
// var_dump ( $in );
|
// var_dump ( $in );
|
||||||
$in = explode ( '|', $in [1], 2 );
|
$in = explode ( '|', $in [1], 2 );
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function decade($zahl)
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function decade(int|float|string $zahl): int|float|string
|
||||||
{
|
{
|
||||||
if (! is_numeric($zahl) || $zahl == 0)
|
if (! is_numeric($zahl) || $zahl == 0)
|
||||||
return $zahl;
|
return $zahl;
|
||||||
@@ -31,7 +33,7 @@ function decade($zahl)
|
|||||||
return $zahl . ' ' . $si[$e];
|
return $zahl . ' ' . $si[$e];
|
||||||
}
|
}
|
||||||
|
|
||||||
function onlyNumeric($num) {
|
function onlyNumeric(string $num): string {
|
||||||
return preg_replace("/[^0-9\.\-]+/", "", $num);
|
return preg_replace("/[^0-9\.\-]+/", "", $num);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
17
og.php
Normal file
17
og.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function scanOG(string $url): array {
|
||||||
|
$og = array();
|
||||||
|
$html = file_get_contents($url);
|
||||||
|
|
||||||
|
$re = '/<meta (name|property)=("|\')(.*?)("|\').*?content=("|\')(.*?)("|\')/m';
|
||||||
|
preg_match_all($re, $html, $matches, PREG_SET_ORDER, 0);
|
||||||
|
|
||||||
|
foreach($matches as $m) {
|
||||||
|
$og[$m[3]] = $m[6];
|
||||||
|
}
|
||||||
|
//print_r($og);
|
||||||
|
return $og;
|
||||||
|
}
|
||||||
|
?>
|
||||||
5058
php-mailer/PHPMailer.php
Normal file
5058
php-mailer/PHPMailer.php
Normal file
File diff suppressed because it is too large
Load Diff
1456
php-mailer/SMTP.php
Normal file
1456
php-mailer/SMTP.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
if (!defined('SQL_LOG')) define ( 'SQL_LOG', 1 ); // schreibt sql querys in eine log
|
if (!defined('SQL_LOG')) define ( 'SQL_LOG', 1 ); // schreibt sql querys in eine log
|
||||||
|
|
||||||
$_m['host'] = 'localhost';
|
$_m['host'] = 'localhost';
|
||||||
$_m['user'] = '';
|
$_m['user'] = '';
|
||||||
$_m['pass'] = '';
|
$_m['pass'] = '';
|
||||||
$_m['data'] = '';
|
$_m['data'] = '';
|
||||||
$_m['pre'] = 'efcms2_';
|
$_m['pre'] = '';
|
||||||
$_m['salt'] = '';
|
$_m['salt'] = '';
|
||||||
|
|
||||||
$_sendermail = 'noreply@troy-grunt.de';
|
$_sendermail = 'noreply@.de';
|
||||||
|
$_smtp['srv'] = 'mail.seemsleg.it';
|
||||||
|
$_smtp['user'] = 'noreply@.de';
|
||||||
|
$_smtp['pw'] = '';
|
||||||
?>
|
?>
|
||||||
20
sql.php
20
sql.php
@@ -1,4 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
class SQL {
|
class SQL {
|
||||||
private $h;
|
private $h;
|
||||||
private $res = false;
|
private $res = false;
|
||||||
@@ -22,7 +24,7 @@ class SQL {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public function get($que, $t = '', $p = array ()) {
|
public function get(string $que, string $t = '', mixed $p = array ()): array|false {
|
||||||
// echo $que;
|
// echo $que;
|
||||||
$this->cnt_get ++;
|
$this->cnt_get ++;
|
||||||
if (SQL_LOG)
|
if (SQL_LOG)
|
||||||
@@ -89,14 +91,14 @@ class SQL {
|
|||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
public function single($que, $t = '', $p = array ()) {
|
public function single(string $que, string $t = '', mixed $p = array ()): array|false {
|
||||||
$data = $this->get ( $que, $t, $p );
|
$data = $this->get ( $que, $t, $p );
|
||||||
if ($data) {
|
if ($data) {
|
||||||
return $data [0];
|
return $data [0];
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public function list($que, $t = '', $p = array ()) {
|
public function list(string $que, string $t = '', mixed $p = array ()): array|false {
|
||||||
$data = $this->get ( $que, $t, $p );
|
$data = $this->get ( $que, $t, $p );
|
||||||
if ($data) {
|
if ($data) {
|
||||||
$ret = array ();
|
$ret = array ();
|
||||||
@@ -109,7 +111,7 @@ class SQL {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public function keyval($que, $k, $v, $t = '', $p = array ()) {
|
public function keyval(string $que, string|int $k, string|int $v, string $t = '', mixed $p = array ()): array|false {
|
||||||
$data = $this->get ( $que, $t, $p );
|
$data = $this->get ( $que, $t, $p );
|
||||||
if ($data) {
|
if ($data) {
|
||||||
$ret = array ();
|
$ret = array ();
|
||||||
@@ -120,7 +122,7 @@ class SQL {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
public function set($que, $t = '', $p = array (), $id = false) {
|
public function set(string $que, string $t = '', mixed $p = array (), bool $id = false): int|false {
|
||||||
// echo $que;
|
// echo $que;
|
||||||
$this->cnt_set ++;
|
$this->cnt_set ++;
|
||||||
$statement = $this->h->prepare ( $que );
|
$statement = $this->h->prepare ( $que );
|
||||||
@@ -166,6 +168,12 @@ class SQL {
|
|||||||
case 10 :
|
case 10 :
|
||||||
$statement->bind_param ( $t, $p [0], $p [1], $p [2], $p [3], $p [4], $p [5], $p [6], $p [7], $p [8], $p [9] );
|
$statement->bind_param ( $t, $p [0], $p [1], $p [2], $p [3], $p [4], $p [5], $p [6], $p [7], $p [8], $p [9] );
|
||||||
break;
|
break;
|
||||||
|
case 11 :
|
||||||
|
$statement->bind_param ( $t, $p [0], $p [1], $p [2], $p [3], $p [4], $p [5], $p [6], $p [7], $p [8], $p [9], $p [10] );
|
||||||
|
break;
|
||||||
|
case 12 :
|
||||||
|
$statement->bind_param ( $t, $p [0], $p [1], $p [2], $p [3], $p [4], $p [5], $p [6], $p [7], $p [8], $p [9], $p [10], $p [11] );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$statement->bind_param ( $t, $p );
|
$statement->bind_param ( $t, $p );
|
||||||
@@ -183,7 +191,7 @@ class SQL {
|
|||||||
return $statement->affected_rows;
|
return $statement->affected_rows;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function __destruct() {
|
function __destruct(): void {
|
||||||
if (SQL_LOG)
|
if (SQL_LOG)
|
||||||
$this->h->close ();
|
$this->h->close ();
|
||||||
// echo 'DESTROY';
|
// echo 'DESTROY';
|
||||||
|
|||||||
30
string.php
30
string.php
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function umlaute($str) {
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function umlaute(string $str): string {
|
||||||
return str_replace ( array (
|
return str_replace ( array (
|
||||||
'Ä',
|
'Ä',
|
||||||
'Ö',
|
'Ö',
|
||||||
@@ -20,10 +22,10 @@ function umlaute($str) {
|
|||||||
'&'
|
'&'
|
||||||
), $str );
|
), $str );
|
||||||
}
|
}
|
||||||
function chk($str) {
|
function chk(string $str): string {
|
||||||
return str_replace ( "'", '"', $str );
|
return str_replace ( "'", '"', $str );
|
||||||
}
|
}
|
||||||
function noScript($str) {
|
function noScript(string $str): string {
|
||||||
return str_replace ( array (
|
return str_replace ( array (
|
||||||
'<',
|
'<',
|
||||||
'>'
|
'>'
|
||||||
@@ -32,43 +34,43 @@ function noScript($str) {
|
|||||||
'>'
|
'>'
|
||||||
), $str );
|
), $str );
|
||||||
}
|
}
|
||||||
function random($name_laenge) {
|
function random(int $name_laenge): string {
|
||||||
$zeichen = "abcedfghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZ0123456789";
|
$zeichen = "abcedfghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTSUVWXYZ0123456789";
|
||||||
$name_neu = "";
|
$name_neu = "";
|
||||||
|
|
||||||
@mt_srand ( ( double ) microtime () * 1000000 );
|
@mt_srand ( ( double ) microtime () * 1000000 );
|
||||||
for($i = 0; $i < $name_laenge; $i ++) {
|
for($i = 0; $i < $name_laenge; $i ++) {
|
||||||
$r = mt_rand ( 0, strlen ( $zeichen ) - 1 );
|
$r = mt_rand ( 0, strlen ( $zeichen ) - 1 );
|
||||||
$name_neu .= $zeichen {$r};
|
$name_neu .= $zeichen[$r];
|
||||||
}
|
}
|
||||||
return $name_neu;
|
return $name_neu;
|
||||||
}
|
}
|
||||||
function startsWith($haystack, $needle) {
|
function startsWith(string $haystack, string $needle): bool {
|
||||||
$length = strlen ( $needle );
|
$length = strlen ( $needle );
|
||||||
return (substr ( $haystack, 0, $length ) === $needle);
|
return (substr ( $haystack, 0, $length ) === $needle);
|
||||||
}
|
}
|
||||||
function endsWith($haystack, $needle) {
|
function endsWith(string $haystack, string $needle): bool {
|
||||||
$length = strlen ( $needle );
|
$length = strlen ( $needle );
|
||||||
|
|
||||||
return $length === 0 || (substr ( $haystack, - $length ) === $needle);
|
return $length === 0 || (substr ( $haystack, - $length ) === $needle);
|
||||||
}
|
}
|
||||||
function onlyAlpha($str, $zus = '') {
|
function onlyAlpha(string $str, string $zus = ''): string {
|
||||||
return preg_replace ( "/[^a-zA-Z0-9 \-\{$zus}_]+/", "", $str );
|
return preg_replace ( "/[^a-zA-Z0-9 \-\{$zus}_]+/", "", $str );
|
||||||
}
|
}
|
||||||
function shortener($str, $len = 50, $fill = '...') {
|
function shortener(string $str, int $len = 50, string $fill = '...'): string {
|
||||||
if (strlen ( $str ) > $len) {
|
if (strlen ( $str ) > $len) {
|
||||||
$str = substr ( $str, 0, $len - strlen ( $fill ) ) . $fill;
|
$str = substr ( $str, 0, $len - strlen ( $fill ) ) . $fill;
|
||||||
}
|
}
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
function isEmail($str) {
|
function isEmail(string $str): string|false {
|
||||||
$match = preg_match ( "/[a-zA-Z0-9\-\_\.]*\@[a-zA-Z0-9\-\_\.]*.[a-z]{2,10}/", $str );
|
$match = preg_match ( "/[a-zA-Z0-9\-\_\.]*\@[a-zA-Z0-9\-\_\.]*.[a-z]{2,10}/", $str );
|
||||||
if ($match) {
|
if ($match) {
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function markUp($text) {
|
function markUp(string $text): string {
|
||||||
$r = '';
|
$r = '';
|
||||||
$lv = 0;
|
$lv = 0;
|
||||||
foreach ( explode ( "\n", $text ) as $t ) {
|
foreach ( explode ( "\n", $text ) as $t ) {
|
||||||
@@ -127,7 +129,7 @@ function markUp($text) {
|
|||||||
}
|
}
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
function onlySimpleHTML($s) {
|
function onlySimpleHTML(string $s): string {
|
||||||
$s = str_replace ( array (
|
$s = str_replace ( array (
|
||||||
'<',
|
'<',
|
||||||
'>'
|
'>'
|
||||||
@@ -259,11 +261,11 @@ function onlySimpleHTML($s) {
|
|||||||
|
|
||||||
return $s;
|
return $s;
|
||||||
}
|
}
|
||||||
function linkify($input) {
|
function linkify(string $input): string {
|
||||||
$pattern = '@(http(s)?://[a-zA-Z0-9/\.\#\-\_]*)@';
|
$pattern = '@(http(s)?://[a-zA-Z0-9/\.\#\-\_]*)@';
|
||||||
return $output = preg_replace ( $pattern, '<a href="$1">$1</a>', $input );
|
return $output = preg_replace ( $pattern, '<a href="$1">$1</a>', $input );
|
||||||
}
|
}
|
||||||
function inStr($needle, $haystack) {
|
function inStr(string $needle, string $haystack): bool {
|
||||||
if (strpos ( $haystack, $needle ) !== false) {
|
if (strpos ( $haystack, $needle ) !== false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
51
troy-api.php
Normal file
51
troy-api.php
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
function sendToTroy(array $data): string|false {
|
||||||
|
$url = 'https://troy-grunt.de/api.php';
|
||||||
|
$options = array (
|
||||||
|
'http' => array (
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => array (
|
||||||
|
'Content-Type: application/json'
|
||||||
|
),
|
||||||
|
'content' => json_encode ( $data )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$context = stream_context_create ( $options );
|
||||||
|
return file_get_contents ( $url, false, $context );
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendToGitea(string $title, string $message): array|null {
|
||||||
|
// secret.php liegt in lib/
|
||||||
|
require 'secret.php';
|
||||||
|
|
||||||
|
$url = rtrim($giteaUrl, '/') . "/repos/$giteaOwner/$giteaRepo/issues";
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
"title" => $title,
|
||||||
|
"body" => $message
|
||||||
|
];
|
||||||
|
|
||||||
|
$options = [
|
||||||
|
'http' => [
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => [
|
||||||
|
"Content-Type: application/json",
|
||||||
|
"Authorization: token $giteaToken"
|
||||||
|
],
|
||||||
|
'content' => json_encode($data)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$context = stream_context_create($options);
|
||||||
|
$result = file_get_contents($url, false, $context);
|
||||||
|
|
||||||
|
if ($result === FALSE) {
|
||||||
|
throw new Exception("Fehler beim Erstellen der Anfrage");
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_decode($result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user