| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/seaside.pacim.de/web/ |
Upload File : |
<?php
/**
* keycards-api.php – Schlüsselschilder-Builder (Phase 1).
*
* action=events GET date[,q] -> { ok, events:[ {title,begin,end} ] }
* action=meta GET date -> { ok, date, cards:[ {id,name,serial,event,begin,end,duration,type} ] }
* action=preview POST date,def -> streamt eine PDF-Vorschau (inline) gemäß Definition
* action=save POST date,def[,name] -> { ok, version:{file,label} } (PDF + JSON-Definition als Variante)
* action=load GET date,file -> { ok, definition:{removed,added} } (Variante zum Weiterbearbeiten)
* action=versions GET date -> { ok, versions:[ {file,created,label} ] }
* action=file GET date,file[,dl] -> streamt eine gespeicherte Varianten-PDF
* action=delete POST date,file -> { ok, versions:[...] }
*
* Definition (JSON): { "removed": ["<invoice_id>|<booking_serial>", ...],
* "added": [ {name,event,begin,end}, ... ] }
* Varianten liegen unter datas/doc-versions/{date}/ als keycards__{Ymd-His}.pdf (+ .json).
*/
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );
ob_start(); // Streu-Ausgaben abfangen (PDF/JSON sauber halten)
if ( ! isset( $_SESSION['user'] ) || $_SESSION['user'] != LOGIN_USER ) {
while ( ob_get_level() > 0 ) ob_end_clean();
http_response_code( 403 );
header( 'Content-Type: application/json; charset=utf-8' );
echo json_encode( array( 'ok' => false, 'error' => 'unauthorized' ) );
exit();
}
$action = isset( $_GET['action'] ) ? $_GET['action'] : ( isset( $_POST['action'] ) ? $_POST['action'] : '' );
/* ---- Helfer ---- */
function kc_date( $v ) { return ( is_string( $v ) && preg_match( '/^\d{4}-\d{2}-\d{2}$/', $v ) ) ? $v : null; }
function kc_dir( $date ) { return PATH_SYSTEM . '/datas/doc-versions/' . $date; }
function kc_json( $arr ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $arr ); exit(); }
function kc_db() { return new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB ); }
/** Definition aus Request (POST['def'] bzw. GET['def']) säubern. */
function kc_definition() {
$raw = isset( $_POST['def'] ) ? $_POST['def'] : ( isset( $_GET['def'] ) ? $_GET['def'] : '' );
$d = ( $raw !== '' ) ? json_decode( $raw, true ) : null;
if ( ! is_array( $d ) ) $d = array();
return array(
'removed' => ( isset( $d['removed'] ) && is_array( $d['removed'] ) ) ? array_values( $d['removed'] ) : array(),
'added' => ( isset( $d['added'] ) && is_array( $d['added'] ) ) ? array_values( $d['added'] ) : array(),
);
}
/** Varianten eines Tages (neueste zuerst). Dateiname: keycards__{Ymd-His}.pdf */
function kc_versions( $date ) {
$dir = kc_dir( $date );
$out = array();
if ( is_dir( $dir ) ) {
foreach ( glob( $dir . '/keycards__*.pdf' ) as $f ) {
$base = basename( $f );
if ( preg_match( '/__(\d{8})-(\d{6})\.pdf$/', $base, $m ) ) {
$ts = mktime( (int) substr( $m[2], 0, 2 ), (int) substr( $m[2], 2, 2 ), (int) substr( $m[2], 4, 2 ),
(int) substr( $m[1], 4, 2 ), (int) substr( $m[1], 6, 2 ), (int) substr( $m[1], 0, 4 ) );
$comment = '';
$jf = $dir . '/' . preg_replace( '/\.pdf$/', '.json', $base );
if ( is_file( $jf ) ) {
$j = json_decode( file_get_contents( $jf ), true );
if ( is_array( $j ) && isset( $j['comment'] ) ) $comment = (string) $j['comment'];
}
$out[] = array(
'file' => $base,
'created' => $ts,
'label' => date( 'd.m.Y, H:i', $ts ) . ' Uhr',
'comment' => $comment,
);
}
}
usort( $out, function ( $a, $b ) { return $b['created'] - $a['created']; } );
}
return $out;
}
/* ====================== EVENTS (Autocomplete) ====================== */
if ( $action === 'events' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
$q = isset( $_GET['q'] ) ? trim( (string) $_GET['q'] ) : '';
$db = kc_db();
$rows = $db->rawQuery(
"SELECT e.event_calendar_title AS title,
DATE_FORMAT(e.event_calendar_begin, '%Y-%m-%d') AS begin,
DATE_FORMAT(e.event_calendar_end, '%Y-%m-%d') AS end
FROM pacim_events e
WHERE DATE_FORMAT(e.event_calendar_begin, '%Y-%m-%d') = ?
ORDER BY e.event_calendar_title ASC", array( $date ) );
$used = $db->rawQuery(
"SELECT b.booking_event AS title, b.booking_begin AS begin, b.booking_end AS end
FROM pacim_booking b
WHERE b.booking_begin = ?
AND b.booking_event IS NOT NULL
AND b.booking_event NOT IN ('', '-', 'Parkplatz')
GROUP BY b.booking_event
ORDER BY b.booking_event ASC", array( $date ) );
$out = array(); $seen = array();
foreach ( array_merge( (array) $rows, (array) $used ) as $r ) {
$title = isset( $r['title'] ) ? trim( $r['title'] ) : '';
if ( $title === '' ) continue;
if ( $q !== '' && stripos( $title, $q ) === false ) continue;
$key = mb_strtolower( $title );
if ( isset( $seen[ $key ] ) ) continue;
$seen[ $key ] = true;
$out[] = array( 'title' => $title, 'begin' => isset( $r['begin'] ) ? $r['begin'] : $date, 'end' => isset( $r['end'] ) ? $r['end'] : '' );
}
kc_json( array( 'ok' => true, 'events' => $out ) );
}
/* ====================== META (Schilder-Liste für den Builder) ====================== */
if ( $action === 'meta' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
require_once( PATH_SYSTEM . '/includes/classes/keycards.gen.php' );
$cards = keycards_meta( kc_db(), $date );
kc_json( array( 'ok' => true, 'date' => $date, 'cards' => $cards ) );
}
/* ====================== SEARCH (Buchungs-Pool: Anreise + Abreise des Tages) ====================== */
if ( $action === 'search' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
require_once( PATH_SYSTEM . '/includes/classes/keycards.gen.php' );
kc_json( array( 'ok' => true, 'date' => $date, 'pool' => keycards_search( kc_db(), $date ) ) );
}
/* ====================== PREVIEW (PDF aus Definition, inline) ====================== */
if ( $action === 'preview' ) {
$date = kc_date( isset( $_POST['date'] ) ? $_POST['date'] : ( isset( $_GET['date'] ) ? $_GET['date'] : '' ) );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
$def = kc_definition();
require_once( PATH_SYSTEM . '/includes/classes/keycards.gen.php' );
$db = kc_db();
$kc = keycards_collect( $db, $date, $def );
$pdf = keycards_render( $db, $date, $kc['bookings'], $kc['events'], $kc['pages'] );
$bytes = $pdf->Output( 'S' );
while ( ob_get_level() > 0 ) ob_end_clean();
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: inline; filename="' . $date . '_schluesselschilder_vorschau.pdf"' );
header( 'Content-Length: ' . strlen( $bytes ) );
header( 'X-Content-Type-Options: nosniff' );
echo $bytes;
exit();
}
/* ====================== SAVE (Variante: PDF + JSON-Definition) ====================== */
if ( $action === 'save' ) {
$date = kc_date( isset( $_POST['date'] ) ? $_POST['date'] : '' );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
$def = kc_definition();
if ( isset( $_POST['name'] ) ) $def['name'] = trim( (string) $_POST['name'] );
if ( isset( $_POST['comment'] ) ) $def['comment'] = trim( (string) $_POST['comment'] );
$dir = kc_dir( $date );
if ( ! is_dir( $dir ) ) @mkdir( $dir, 0775, true );
if ( ! is_dir( $dir ) || ! is_writable( $dir ) ) kc_json( array( 'ok' => false, 'error' => 'not_writable' ) );
require_once( PATH_SYSTEM . '/includes/classes/keycards.gen.php' );
$db = kc_db();
$kc = keycards_collect( $db, $date, $def );
$pdf = keycards_render( $db, $date, $kc['bookings'], $kc['events'], $kc['pages'] );
$ts = date( 'Ymd-His' );
$fname = 'keycards__' . $ts . '.pdf';
$pdf->Output( 'F', $dir . '/' . $fname );
@file_put_contents( $dir . '/keycards__' . $ts . '.json', json_encode( $def ) );
if ( ! is_file( $dir . '/' . $fname ) ) kc_json( array( 'ok' => false, 'error' => 'write_failed' ) );
kc_json( array( 'ok' => true, 'version' => array(
'file' => $fname,
'label' => date( 'd.m.Y, H:i', time() ) . ' Uhr',
) ) );
}
/* ====================== LOAD (Definition einer Variante) ====================== */
if ( $action === 'load' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
$file = isset( $_GET['file'] ) ? basename( $_GET['file'] ) : '';
if ( ! $date || ! preg_match( '/^keycards__\d{8}-\d{6}\.pdf$/', $file ) ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
$json = kc_dir( $date ) . '/' . preg_replace( '/\.pdf$/', '.json', $file );
$def = is_file( $json ) ? json_decode( file_get_contents( $json ), true ) : array();
if ( ! is_array( $def ) ) $def = array();
kc_json( array( 'ok' => true, 'definition' => array(
'removed' => ( isset( $def['removed'] ) && is_array( $def['removed'] ) ) ? array_values( $def['removed'] ) : array(),
'added' => ( isset( $def['added'] ) && is_array( $def['added'] ) ) ? array_values( $def['added'] ) : array(),
'name' => isset( $def['name'] ) ? $def['name'] : '',
'comment' => isset( $def['comment'] ) ? $def['comment'] : '',
) ) );
}
/* ====================== VERSIONS (Varianten-Liste) ====================== */
if ( $action === 'versions' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
if ( ! $date ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
kc_json( array( 'ok' => true, 'versions' => kc_versions( $date ) ) );
}
/* ====================== FILE (Varianten-PDF streamen) ====================== */
if ( $action === 'file' ) {
$date = kc_date( isset( $_GET['date'] ) ? $_GET['date'] : '' );
$file = isset( $_GET['file'] ) ? basename( $_GET['file'] ) : '';
if ( ! $date || ! preg_match( '/^keycards__\d{8}-\d{6}\.pdf$/', $file ) ) { while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 400 ); echo 'bad request'; exit(); }
$path = kc_dir( $date ) . '/' . $file;
if ( ! is_file( $path ) ) { while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 404 ); echo 'not found'; exit(); }
$dl = isset( $_GET['dl'] ) && $_GET['dl'] == '1';
$down = $date . '-Schluesselschilder-Variante.pdf';
while ( ob_get_level() > 0 ) ob_end_clean();
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: ' . ( $dl ? 'attachment' : 'inline' ) . '; filename="' . $down . '"' );
header( 'Content-Length: ' . filesize( $path ) );
header( 'X-Content-Type-Options: nosniff' );
readfile( $path );
exit();
}
/* ====================== DELETE (Variante entfernen) ====================== */
if ( $action === 'delete' ) {
$date = kc_date( isset( $_POST['date'] ) ? $_POST['date'] : '' );
$file = isset( $_POST['file'] ) ? basename( $_POST['file'] ) : '';
if ( ! $date || ! preg_match( '/^keycards__\d{8}-\d{6}\.pdf$/', $file ) ) kc_json( array( 'ok' => false, 'error' => 'bad_params' ) );
$path = kc_dir( $date ) . '/' . $file;
if ( ! is_file( $path ) ) kc_json( array( 'ok' => false, 'error' => 'not_found' ) );
@unlink( $path );
@unlink( kc_dir( $date ) . '/' . preg_replace( '/\.pdf$/', '.json', $file ) );
if ( is_file( $path ) ) kc_json( array( 'ok' => false, 'error' => 'delete_failed' ) );
kc_json( array( 'ok' => true, 'versions' => kc_versions( $date ) ) );
}
http_response_code( 400 );
kc_json( array( 'ok' => false, 'error' => 'unknown_action' ) );