Compare commits
48 Commits
feature/ma
...
644e03da9b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
644e03da9b | ||
|
|
cb115bac40 | ||
|
|
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 | ||
|
|
31a0a02366 | ||
|
|
233c9f5aed | ||
|
|
9c034cd935 | ||
|
|
d32ad04722 | ||
|
|
32c65f7da1 | ||
|
|
f736789f5b | ||
|
|
973a0a1d01 | ||
|
|
de82116482 | ||
|
|
5c7e2f6a8f |
92
NEXT_STEPS.md
Normal file
92
NEXT_STEPS.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# 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 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.
|
||||||
|
|
||||||
|
- Code-Qualitaet (aufgeteilt in Unter-Issues)
|
||||||
|
- Aufwand: `L`
|
||||||
|
- Labels: `quality`, `refactor`
|
||||||
|
- Unter-Issues:
|
||||||
|
- Define and enforce naming conventions for functions, files and constants.
|
||||||
|
- Refactor SQL binding helpers to one consistent, typed API surface.
|
||||||
|
- Mark legacy functions/modules (`@deprecated`) and document replacement path.
|
||||||
|
- Consolidate Markdown docs (README + API notes) into one canonical structure.
|
||||||
|
- Clarify module boundaries and ownership (I/O, SQL, parsing, formatting).
|
||||||
|
- Akzeptanzkriterien:
|
||||||
|
- Kurzer Styleguide in `README.md` vorhanden und auf bestehende Dateien angewendet.
|
||||||
|
- Keine neuen Legacy-Einstiege ohne Markierung und Migrationshinweis.
|
||||||
|
- SQL-Helper nutzen einheitliche Signaturen in geaenderten Modulen.
|
||||||
|
- Modulgrenzen sind in Doku und Dateistruktur konsistent nachvollziehbar.
|
||||||
|
|
||||||
|
- #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
|
||||||
201
README.md
201
README.md
@@ -1,2 +1,203 @@
|
|||||||
# 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`)
|
||||||
|
- `http-limits.php`: Zentrale HTTP-Limits (`httpLimits`)
|
||||||
|
- `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';
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP-Defaults fuer Netzwerkmodule (`link-meta.php`, `og.php`):
|
||||||
|
|
||||||
|
- `LIB_HTTP_TIMEOUT = 8` (Sekunden)
|
||||||
|
- `LIB_HTTP_MAX_REDIRECTS = 4`
|
||||||
|
- `LIB_HTTP_MAX_BYTES = 5242880` (5 MiB)
|
||||||
|
|
||||||
|
Optional vor dem Include ueberschreiben:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
define('LIB_HTTP_TIMEOUT', 10);
|
||||||
|
define('LIB_HTTP_MAX_REDIRECTS', 5);
|
||||||
|
define('LIB_HTTP_MAX_BYTES', 8 * 1024 * 1024);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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{
|
||||||
|
|||||||
24
http-limits.php
Normal file
24
http-limits.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
if (!defined('LIB_HTTP_TIMEOUT')) {
|
||||||
|
define('LIB_HTTP_TIMEOUT', 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('LIB_HTTP_MAX_REDIRECTS')) {
|
||||||
|
define('LIB_HTTP_MAX_REDIRECTS', 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('LIB_HTTP_MAX_BYTES')) {
|
||||||
|
define('LIB_HTTP_MAX_BYTES', 5 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
function httpLimits(): array {
|
||||||
|
return [
|
||||||
|
'timeout' => max(1, (int) LIB_HTTP_TIMEOUT),
|
||||||
|
'max_redirects' => max(0, (int) LIB_HTTP_MAX_REDIRECTS),
|
||||||
|
'max_bytes' => max(1, (int) LIB_HTTP_MAX_BYTES),
|
||||||
|
'user_agent' => 'star-citizen.de-linkbot/1.0'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,18 +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.124', // bing bot
|
'192.99.5.225', // ...
|
||||||
'54.36.148.', // ahrefbot
|
'205.185.115.87', //sex spam
|
||||||
|
'207.46.13.', // bing bot
|
||||||
|
'216.58.', //google
|
||||||
'216.244.66.196', // opensiteexplorer
|
'216.244.66.196', // opensiteexplorer
|
||||||
'65.21.180.26', // seekport
|
'2a01:4f8:190:4244::2', // mj12bot
|
||||||
'81.209.177.145', // website-datenbank.de
|
'2a01:4f8:162:43c5::2', // mj12bot
|
||||||
'2a01:4f8:190:4244::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;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
187
link-meta.php
Normal file
187
link-meta.php
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/http-limits.php';
|
||||||
|
|
||||||
|
function httpContext(?int $timeout = null) {
|
||||||
|
$limits = httpLimits();
|
||||||
|
$resolvedTimeout = $timeout === null ? $limits['timeout'] : max(1, $timeout);
|
||||||
|
return stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'timeout' => $resolvedTimeout,
|
||||||
|
'follow_location' => 1,
|
||||||
|
'max_redirects' => $limits['max_redirects'],
|
||||||
|
'user_agent' => $limits['user_agent'],
|
||||||
|
'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 = null): ?string {
|
||||||
|
$limits = httpLimits();
|
||||||
|
$ctx = httpContext($timeout);
|
||||||
|
$content = @file_get_contents($url, false, $ctx);
|
||||||
|
if ($content === false || strlen($content) > $limits['max_bytes']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $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);
|
||||||
|
if ($imageContent === null || strlen($imageContent) === 0) {
|
||||||
|
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);
|
||||||
|
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!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|||||||
85
markdown.php
Normal file
85
markdown.php
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
// TODO markdown imple
|
||||||
|
function md(string $str): string {
|
||||||
|
// return nl2br ( $str ); // TODO md problem
|
||||||
|
$text = '<p>';
|
||||||
|
$lv = 0;
|
||||||
|
$str = explode ( "\n", str_replace ( "\r\n", "\n", $str ) );
|
||||||
|
// var_dump ( $str );
|
||||||
|
foreach ( $str as $t ) {
|
||||||
|
// echo '<pre>' . $t . '</pre>';
|
||||||
|
$t = preg_replace_callback ( '/\[\[([^\]]*)\]\]/m', '_md_link_replacer', $t );
|
||||||
|
$nlv = 0;
|
||||||
|
if (startsWith ( $t, '**** ' )) {
|
||||||
|
// echo - 1;
|
||||||
|
$t = substr ( $t, 5 );
|
||||||
|
$nlv = 4;
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '*** ' )) {
|
||||||
|
// echo - 2;
|
||||||
|
$t = substr ( $t, 4 );
|
||||||
|
$nlv = 3;
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '** ' )) {
|
||||||
|
// echo - 3;
|
||||||
|
$t = substr ( $t, 3 );
|
||||||
|
$nlv = 2;
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '* ' )) {
|
||||||
|
// echo - 4;
|
||||||
|
$t = substr ( $t, 2 );
|
||||||
|
$nlv = 1;
|
||||||
|
}
|
||||||
|
if ($lv != $nlv) {
|
||||||
|
while ( $lv < $nlv ) {
|
||||||
|
// echo '-5 (' . $lv . '-' . $nlv . ')';
|
||||||
|
$text .= '<ul>';
|
||||||
|
$lv ++;
|
||||||
|
}
|
||||||
|
while ( $lv > $nlv ) {
|
||||||
|
// echo '-6 (' . $lv . '-' . $nlv . ')';
|
||||||
|
$text .= '</ul>';
|
||||||
|
$lv --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '!!!!! ' )) {
|
||||||
|
$t = '<h5>' . substr ( $t, 6 ) . '</h5>';
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '!!!! ' )) {
|
||||||
|
$t = '<h4>' . substr ( $t, 5 ) . '</h4>';
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '!!! ' )) {
|
||||||
|
$t = '<h3>' . substr ( $t, 4 ) . '</h3>';
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '!! ' )) {
|
||||||
|
$t = '<h2>' . substr ( $t, 3 ) . '</h2>';
|
||||||
|
}
|
||||||
|
if (startsWith ( $t, '! ' )) {
|
||||||
|
$t = '<h1>' . substr ( $t, 2 ) . '</h1>';
|
||||||
|
}
|
||||||
|
if ($lv == 0) {
|
||||||
|
if ($t == '') {
|
||||||
|
$text .= '</p><p>';
|
||||||
|
} else {
|
||||||
|
$text .= $t;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$text .= '<li>' . $t . '</li>';
|
||||||
|
}
|
||||||
|
// var_dump ( $t );
|
||||||
|
}
|
||||||
|
while ( $lv > 0 ) {
|
||||||
|
$text .= '</ul>';
|
||||||
|
$lv --;
|
||||||
|
}
|
||||||
|
$text .= '</p>';
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
function _md_link_replacer(array $in): string {
|
||||||
|
// var_dump ( $in );
|
||||||
|
$in = explode ( '|', $in [1], 2 );
|
||||||
|
|
||||||
|
return '<a href="' . $in [0] . '" target="_blank">' . (isset ( $in [1] ) ? $in [1] : $in [0]) . '</a>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
35
og.php
Normal file
35
og.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
require_once __DIR__ . '/http-limits.php';
|
||||||
|
|
||||||
|
function scanOG(string $url): array {
|
||||||
|
$og = array();
|
||||||
|
$limits = httpLimits();
|
||||||
|
$ctx = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'timeout' => $limits['timeout'],
|
||||||
|
'follow_location' => 1,
|
||||||
|
'max_redirects' => $limits['max_redirects'],
|
||||||
|
'user_agent' => $limits['user_agent'],
|
||||||
|
'ignore_errors' => true
|
||||||
|
],
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer' => true,
|
||||||
|
'verify_peer_name' => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$html = @file_get_contents($url, false, $ctx);
|
||||||
|
if ($html === false || strlen($html) > $limits['max_bytes']) {
|
||||||
|
return $og;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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'] = '';
|
||||||
?>
|
?>
|
||||||
31
sql.php
31
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)
|
||||||
@@ -34,6 +36,7 @@ class SQL {
|
|||||||
''
|
''
|
||||||
), $que ) . "\n" . print_r ( $p, true ) . "\n\n" );
|
), $que ) . "\n" . print_r ( $p, true ) . "\n\n" );
|
||||||
$statement = $this->h->prepare ( $que );
|
$statement = $this->h->prepare ( $que );
|
||||||
|
if (is_array ( $p )) {
|
||||||
switch (count ( $p )) {
|
switch (count ( $p )) {
|
||||||
case 0 :
|
case 0 :
|
||||||
break;
|
break;
|
||||||
@@ -68,6 +71,9 @@ class SQL {
|
|||||||
$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;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$statement->bind_param ( $t, $p );
|
||||||
|
}
|
||||||
$statement->execute ();
|
$statement->execute ();
|
||||||
|
|
||||||
$ret = array ();
|
$ret = array ();
|
||||||
@@ -85,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 ();
|
||||||
@@ -105,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 ();
|
||||||
@@ -116,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 );
|
||||||
@@ -128,6 +134,7 @@ class SQL {
|
|||||||
' ',
|
' ',
|
||||||
''
|
''
|
||||||
), $que ) . "\n" . print_r ( $p, true ) . "\n\n" );
|
), $que ) . "\n" . print_r ( $p, true ) . "\n\n" );
|
||||||
|
if (is_array ( $p )) {
|
||||||
switch (count ( $p )) {
|
switch (count ( $p )) {
|
||||||
case 0 :
|
case 0 :
|
||||||
break;
|
break;
|
||||||
@@ -167,15 +174,9 @@ class SQL {
|
|||||||
case 12 :
|
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] );
|
$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;
|
break;
|
||||||
case 13 :
|
}
|
||||||
$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], $p [12] );
|
} else {
|
||||||
break;
|
$statement->bind_param ( $t, $p );
|
||||||
case 14 :
|
|
||||||
$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], $p [12], $p [13] );
|
|
||||||
break;
|
|
||||||
case 15 :
|
|
||||||
$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], $p [12], $p [13], $p [14] );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
$statement->execute ();
|
$statement->execute ();
|
||||||
if (isset ( $statement->error ) && $statement->error != '') {
|
if (isset ( $statement->error ) && $statement->error != '') {
|
||||||
@@ -190,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';
|
||||||
|
|||||||
243
string.php
243
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 (
|
||||||
'Ä',
|
'Ä',
|
||||||
'Ö',
|
'Ö',
|
||||||
@@ -7,7 +9,8 @@ function umlaute($str) {
|
|||||||
'ä',
|
'ä',
|
||||||
'ö',
|
'ö',
|
||||||
'ü',
|
'ü',
|
||||||
'ß'
|
'ß',
|
||||||
|
'&'
|
||||||
), array (
|
), array (
|
||||||
'Ä',
|
'Ä',
|
||||||
'Ö',
|
'Ö',
|
||||||
@@ -15,13 +18,14 @@ 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 (
|
||||||
'<',
|
'<',
|
||||||
'>'
|
'>'
|
||||||
@@ -30,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 ) {
|
||||||
@@ -125,143 +129,94 @@ function markUp($text) {
|
|||||||
}
|
}
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
function onlySimpleHTML($s) {
|
function onlySimpleHTML(string $s, ?array $allowedTags = null): string {
|
||||||
$s = str_replace ( array (
|
if ($s === '') {
|
||||||
'<',
|
return '';
|
||||||
'>'
|
}
|
||||||
), array (
|
|
||||||
'{{|-<-|}}',
|
|
||||||
'{{|->-|}}'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}b{{|->-|}}',
|
|
||||||
'{{|-<-|}}b/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<b>',
|
|
||||||
'<b/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}u{{|->-|}}',
|
|
||||||
'{{|-<-|}}u/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<u>',
|
|
||||||
'<u/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}i{{|->-|}}',
|
|
||||||
'{{|-<-|}}i/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<i>',
|
|
||||||
'<i/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}span{{|->-|}}',
|
|
||||||
'{{|-<-|}}span/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<span>',
|
|
||||||
'<span/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}b{{|->-|}}',
|
|
||||||
'{{|-<-|}}b/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<b>',
|
|
||||||
'<b/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}br{{|->-|}}',
|
|
||||||
'{{|-<-|}}br/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<br>',
|
|
||||||
'<br/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h1{{|->-|}}',
|
|
||||||
'{{|-<-|}}h1/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h1>',
|
|
||||||
'<h1/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h2{{|->-|}}',
|
|
||||||
'{{|-<-|}}h2/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h2>',
|
|
||||||
'<h2/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h3{{|->-|}}',
|
|
||||||
'{{|-<-|}}h3/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h3>',
|
|
||||||
'<h3/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h4{{|->-|}}',
|
|
||||||
'{{|-<-|}}h4/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h4>',
|
|
||||||
'<h4/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h5{{|->-|}}',
|
|
||||||
'{{|-<-|}}h5/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h5>',
|
|
||||||
'<h5/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}h6{{|->-|}}',
|
|
||||||
'{{|-<-|}}h6/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<h6>',
|
|
||||||
'<h6/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}li{{|->-|}}',
|
|
||||||
'{{|-<-|}}li/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<li>',
|
|
||||||
'<li/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}ul{{|->-|}}',
|
|
||||||
'{{|-<-|}}ul/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<ul>',
|
|
||||||
'<ul/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}ol{{|->-|}}',
|
|
||||||
'{{|-<-|}}ol/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<ol>',
|
|
||||||
'<ol/>'
|
|
||||||
), $s );
|
|
||||||
$s = str_replace ( array (
|
|
||||||
'{{|-<-|}}pre{{|->-|}}',
|
|
||||||
'{{|-<-|}}pre/{{|->-|}}'
|
|
||||||
), array (
|
|
||||||
'<pre>',
|
|
||||||
'<pre/>'
|
|
||||||
), $s );
|
|
||||||
|
|
||||||
// cleanup
|
if ($allowedTags === null) {
|
||||||
$s = str_replace ( array (
|
$allowedTags = array (
|
||||||
'{{|-',
|
'b',
|
||||||
'-|}}'
|
'u',
|
||||||
), array (
|
'i',
|
||||||
'',
|
'span',
|
||||||
''
|
'br',
|
||||||
), $s );
|
'h1',
|
||||||
|
'h2',
|
||||||
|
'h3',
|
||||||
|
'h4',
|
||||||
|
'h5',
|
||||||
|
'h6',
|
||||||
|
'li',
|
||||||
|
'ul',
|
||||||
|
'ol',
|
||||||
|
'pre'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $s;
|
$allow = array_fill_keys ( array_map ( 'strtolower', $allowedTags ), true );
|
||||||
|
$selfClosing = array (
|
||||||
|
'br' => true
|
||||||
|
);
|
||||||
|
|
||||||
|
$parts = preg_split ( '/(<[^>]*>)/', $s, - 1, PREG_SPLIT_DELIM_CAPTURE );
|
||||||
|
if ($parts === false) {
|
||||||
|
return htmlspecialchars ( $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = '';
|
||||||
|
foreach ( $parts as $part ) {
|
||||||
|
if ($part === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($part[0] !== '<') {
|
||||||
|
$out .= $part;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match ( '/^<\s*(\/?)\s*([a-z0-9]+)\s*(\/?)\s*>$/i', $part, $m ) !== 1) {
|
||||||
|
$out .= htmlspecialchars ( $part, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isClose = ($m[1] === '/');
|
||||||
|
$tag = strtolower ( $m[2] );
|
||||||
|
$isSelfClose = ($m[3] === '/');
|
||||||
|
|
||||||
|
if (! isset ( $allow[$tag] )) {
|
||||||
|
$out .= htmlspecialchars ( $part, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isClose) {
|
||||||
|
if (isset ( $selfClosing[$tag] )) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$out .= "</{$tag}>";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($isSelfClose && ! isset ( $selfClosing[$tag] )) {
|
||||||
|
$out .= "</{$tag}>";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset ( $selfClosing[$tag] )) {
|
||||||
|
$out .= "<{$tag}>";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= "<{$tag}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
}
|
}
|
||||||
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