403Webshell
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 :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/seaside.pacim.de/web//terminals-api.php
<?php
/**
 * terminals-api.php – Backoffice-Endpunkt für Terminals (Einstellungen → Terminals). Nur Admins.
 * Aktionen (action=): list | get | create | update | delete | toggle | qr | accesses
 */
require_once( __DIR__ . '/includes/config.inc.php' );
require_once( __DIR__ . '/includes/mobileaccess.php' );
require_once( __DIR__ . '/includes/terminals.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );

function tm_json( $a ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $a ); exit(); }
function tm_fail( $m ) { tm_json( array( 'ok' => false, 'error' => $m ) ); }

if ( ! function_exists( 'is_admin' ) || ! is_admin() ) tm_fail( 'Nicht berechtigt.' );

$action = (string) ( $_GET['action'] ?? ( $_POST['action'] ?? '' ) );
$db = new MysqliDb( MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB );
pacim_terminal_ensure_table( $db );
pacim_ma_ensure_table( $db );

function tm_url( $hash ) { return SITE_URL . '/terminal.php?h=' . $hash; }
function tm_qr_png( $url, $size = 8 ) {
    require_once( PATH_SYSTEM . '/includes/plugins/tcpdf/tcpdf_barcodes_2d.php' );
    $bc = new TCPDF2DBarcode( (string) $url, 'QRCODE,M' );
    return $bc->getBarcodePngData( $size, $size, array( 13, 44, 68 ) );
}
function tm_access_item( $m ) {
    return array(
        'id' => (int) $m['ma_id'], 'label' => (string) $m['ma_label'],
        'date' => substr( (string) $m['ma_date'], 0, 10 ),
        'has_pin' => ( (string) $m['ma_pin'] !== '' ),
        'summary' => function_exists( 'pacim_ma_summary' ) ? pacim_ma_summary( $m ) : array(),
    );
}
function tm_result( $db, $id ) {
    $t = $db->rawQueryOne( "SELECT * FROM pacim_terminals WHERE terminal_id = ?", array( (int) $id ) );
    if ( ! $t ) return array( 'ok' => false, 'error' => 'Terminal nicht gefunden.' );
    $url = tm_url( $t['terminal_hash'] );
    $acc = array(); foreach ( pacim_terminal_accesses( $db, $id ) as $m ) $acc[] = tm_access_item( $m );
    $logins = array();
    foreach ( pacim_terminal_logins( $db, $id, false ) as $lg ) $logins[] = array(
        'id' => (int) $lg['tl_id'], 'name' => (string) $lg['tl_name'], 'email' => (string) $lg['tl_email'],
        'expires' => ! empty( $lg['tl_expires'] ) ? date( 'Y-m-d\TH:i', strtotime( $lg['tl_expires'] ) ) : '',
        'active' => (int) $lg['tl_active'], 'has_pin' => ( (string) $lg['tl_pin'] !== '' ),
    );
    return array(
        'ok' => true, 'id' => (int) $t['terminal_id'], 'hash' => $t['terminal_hash'],
        'label' => (string) $t['terminal_label'], 'email' => (string) $t['terminal_email'],
        'active' => (int) $t['terminal_active'], 'has_pin' => ( (string) $t['terminal_pin'] !== '' ),
        'url' => $url, 'qr' => 'data:image/png;base64,' . base64_encode( tm_qr_png( $url, 8 ) ),
        'accesses' => $acc, 'accessIds' => pacim_terminal_access_ids( $db, $id ),
        'logins' => $logins,
    );
}

/* ---- QR (Bildquelle) ---- */
if ( $action === 'qr' ) {
    $hash = preg_replace( '/[^a-f0-9]/', '', strtolower( (string) ( $_GET['hash'] ?? '' ) ) );
    if ( $hash === '' ) { http_response_code( 404 ); exit(); }
    while ( ob_get_level() > 0 ) ob_end_clean();
    header( 'Content-Type: image/png' ); header( 'Cache-Control: public, max-age=3600' );
    echo tm_qr_png( tm_url( $hash ), 8 ); exit();
}

/* ---- Verfügbare Mobile-Zugänge (zum Zuordnen) ---- */
if ( $action === 'accesses' ) {
    $rows = (array) $db->rawQuery( "SELECT * FROM pacim_mobile_access WHERE ma_active = 1 ORDER BY ma_date DESC, ma_id DESC LIMIT 500" );
    $out = array(); foreach ( $rows as $m ) $out[] = tm_access_item( $m );
    tm_json( array( 'ok' => true, 'accesses' => $out ) );
}

/* ---- Liste ---- */
if ( $action === 'list' ) {
    $rows = (array) $db->rawQuery( "SELECT * FROM pacim_terminals ORDER BY terminal_active DESC, terminal_id DESC" );
    $items = array();
    foreach ( $rows as $t ) {
        $cnt = $db->rawQueryOne( "SELECT COUNT(*) c FROM pacim_terminal_access WHERE terminal_id = ?", array( (int) $t['terminal_id'] ) );
        $items[] = array(
            'id' => (int) $t['terminal_id'], 'hash' => $t['terminal_hash'],
            'label' => (string) $t['terminal_label'], 'email' => (string) $t['terminal_email'],
            'active' => (int) $t['terminal_active'], 'has_pin' => ( (string) $t['terminal_pin'] !== '' ),
            'url' => tm_url( $t['terminal_hash'] ), 'qr_url' => SITE_URL . '/terminals-api.php?action=qr&hash=' . $t['terminal_hash'],
            'count' => $cnt ? (int) $cnt['c'] : 0,
        );
    }
    tm_json( array( 'ok' => true, 'terminals' => $items ) );
}

/* ---- Einzeln (für Editor) ---- */
if ( $action === 'get' ) {
    tm_json( tm_result( $db, (int) ( $_GET['id'] ?? 0 ) ) );
}

/* ---- Anlegen ---- */
if ( $action === 'create' ) {
    $label = trim( mb_substr( (string) ( $_POST['label'] ?? '' ), 0, 190 ) );
    $email = trim( mb_substr( (string) ( $_POST['email'] ?? '' ), 0, 190 ) );
    if ( $label === '' ) tm_fail( 'Bitte eine Bezeichnung angeben.' );
    if ( $email !== '' && ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) tm_fail( 'Ungültige E-Mail-Adresse.' );
    // Master-PIN optional: leer = Terminal nutzt stattdessen Login-Zugänge (oder ist offen).
    $pin = preg_replace( '/\D/', '', (string) ( $_POST['pin'] ?? '' ) );
    if ( $pin !== '' && ( strlen( $pin ) < 4 || strlen( $pin ) > 10 ) ) tm_fail( 'PIN muss 4–10 Ziffern haben.' );
    $hash = '';
    for ( $i = 0; $i < 6; $i++ ) { $cand = bin2hex( random_bytes( 12 ) );
        if ( ! $db->rawQueryOne( "SELECT 1 x FROM pacim_terminals WHERE terminal_hash = ?", array( $cand ) ) ) { $hash = $cand; break; } }
    if ( $hash === '' ) tm_fail( 'Hash-Erzeugung fehlgeschlagen.' );
    $ok = $db->insert( 'pacim_terminals', array(
        'terminal_hash' => $hash, 'terminal_label' => $label, 'terminal_email' => $email,
        'terminal_pin' => ( $pin !== '' ? pacim_terminal_pin_hash( $hash, $pin ) : '' ),
        'terminal_active' => ( isset( $_POST['active'] ) && empty( $_POST['active'] ) ) ? 0 : 1,
        'terminal_created' => date( 'Y-m-d H:i:s' ),
        'terminal_created_by' => function_exists( 'current_user_id' ) ? current_user_id() : 0,
        'terminal_created_name' => trim( (string) ( $_SESSION['user_name'] ?? '' ) ),
    ) );
    if ( ! $ok ) tm_fail( 'Konnte nicht angelegt werden.' );
    $ids = isset( $_POST['ids'] ) ? array_map( 'intval', explode( ',', (string) $_POST['ids'] ) ) : array();
    pacim_terminal_set_access( $db, (int) $ok, $ids );
    tm_json( tm_result( $db, (int) $ok ) );
}

/* ---- Bearbeiten ---- */
if ( $action === 'update' ) {
    $id = (int) ( $_POST['id'] ?? 0 );
    $t = $db->rawQueryOne( "SELECT * FROM pacim_terminals WHERE terminal_id = ?", array( $id ) );
    if ( ! $t ) tm_fail( 'Terminal nicht gefunden.' );
    $label = trim( mb_substr( (string) ( $_POST['label'] ?? '' ), 0, 190 ) );
    $email = trim( mb_substr( (string) ( $_POST['email'] ?? '' ), 0, 190 ) );
    if ( $label === '' ) tm_fail( 'Bitte eine Bezeichnung angeben.' );
    if ( $email !== '' && ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) tm_fail( 'Ungültige E-Mail-Adresse.' );
    $upd = array( 'terminal_label' => $label, 'terminal_email' => $email );
    // PIN: leer = unverändert; 4–10 Ziffern = neue PIN.
    $pin = preg_replace( '/\D/', '', (string) ( $_POST['pin'] ?? '' ) );
    if ( $pin !== '' ) { if ( strlen( $pin ) < 4 || strlen( $pin ) > 10 ) tm_fail( 'PIN muss 4–10 Ziffern haben.' ); $upd['terminal_pin'] = pacim_terminal_pin_hash( $t['terminal_hash'], $pin ); }
    $db->where( 'terminal_id', $id );
    if ( $db->update( 'pacim_terminals', $upd ) === false ) tm_fail( 'Konnte nicht gespeichert werden.' );
    if ( isset( $_POST['ids'] ) ) pacim_terminal_set_access( $db, $id, array_map( 'intval', array_filter( explode( ',', (string) $_POST['ids'] ) ) ) );
    tm_json( tm_result( $db, $id ) );
}

/* ---- Aktiv/Inaktiv ---- */
if ( $action === 'toggle' ) {
    $id = (int) ( $_POST['id'] ?? 0 );
    $t = $db->rawQueryOne( "SELECT terminal_active FROM pacim_terminals WHERE terminal_id = ?", array( $id ) );
    if ( ! $t ) tm_fail( 'Terminal nicht gefunden.' );
    $new = (int) $t['terminal_active'] ? 0 : 1;
    $db->where( 'terminal_id', $id ); $db->update( 'pacim_terminals', array( 'terminal_active' => $new ) );
    tm_json( array( 'ok' => true, 'active' => $new ) );
}

/* ---- Löschen ---- */
if ( $action === 'delete' ) {
    $id = (int) ( $_POST['id'] ?? 0 );
    $db->where( 'terminal_id', $id ); $db->delete( 'pacim_terminals' );
    $db->where( 'terminal_id', $id ); $db->delete( 'pacim_terminal_access' );
    tm_json( array( 'ok' => true ) );
}

/* ---- Login-Zugang anlegen/bearbeiten ---- */
if ( $action === 'login_save' ) {
    $tid = (int) ( $_POST['terminal'] ?? 0 );
    $t = $db->rawQueryOne( "SELECT * FROM pacim_terminals WHERE terminal_id = ?", array( $tid ) );
    if ( ! $t ) tm_fail( 'Terminal nicht gefunden.' );
    $lid   = (int) ( $_POST['id'] ?? 0 );
    $name  = trim( mb_substr( (string) ( $_POST['name'] ?? '' ), 0, 120 ) );
    $email = trim( mb_substr( (string) ( $_POST['email'] ?? '' ), 0, 190 ) );
    if ( $name === '' ) tm_fail( 'Bitte einen Anzeigenamen angeben.' );
    if ( $email !== '' && ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) tm_fail( 'Ungültige E-Mail-Adresse.' );
    $exp = null; $exRaw = trim( (string) ( $_POST['expires'] ?? '' ) );
    if ( $exRaw !== '' ) { $ts = strtotime( str_replace( 'T', ' ', $exRaw ) ); if ( $ts ) $exp = date( 'Y-m-d H:i:s', $ts ); }
    $active = ( isset( $_POST['active'] ) && empty( $_POST['active'] ) ) ? 0 : 1;
    $pin = preg_replace( '/\D/', '', (string) ( $_POST['pin'] ?? '' ) );
    if ( $lid > 0 ) {
        $lg = pacim_terminal_login_get( $db, $lid );
        if ( ! $lg || (int) $lg['tl_terminal'] !== $tid ) tm_fail( 'Login nicht gefunden.' );
        $upd = array( 'tl_name' => $name, 'tl_email' => $email, 'tl_expires' => $exp, 'tl_active' => $active );
        if ( $pin !== '' ) { if ( strlen( $pin ) < 4 || strlen( $pin ) > 10 ) tm_fail( 'PIN muss 4–10 Ziffern haben.' ); $upd['tl_pin'] = pacim_terminal_login_pin_hash( $t['terminal_hash'], $lid, $pin ); }
        $db->where( 'tl_id', $lid ); if ( $db->update( 'pacim_terminal_logins', $upd ) === false ) tm_fail( 'Konnte nicht gespeichert werden.' );
    } else {
        if ( strlen( $pin ) < 4 || strlen( $pin ) > 10 ) tm_fail( 'PIN muss 4–10 Ziffern haben.' );
        $newId = $db->insert( 'pacim_terminal_logins', array(
            'tl_terminal' => $tid, 'tl_name' => $name, 'tl_email' => $email, 'tl_expires' => $exp,
            'tl_active' => $active, 'tl_pin' => '', 'tl_created' => date( 'Y-m-d H:i:s' ) ) );
        if ( ! $newId ) tm_fail( 'Konnte nicht angelegt werden.' );
        $db->where( 'tl_id', (int) $newId ); $db->update( 'pacim_terminal_logins', array( 'tl_pin' => pacim_terminal_login_pin_hash( $t['terminal_hash'], (int) $newId, $pin ) ) );
    }
    tm_json( tm_result( $db, $tid ) );
}

/* ---- Login-Zugang löschen ---- */
if ( $action === 'login_delete' ) {
    $lid = (int) ( $_POST['id'] ?? 0 ); $tid = (int) ( $_POST['terminal'] ?? 0 );
    $db->where( 'tl_id', $lid ); $db->where( 'tl_terminal', $tid ); $db->delete( 'pacim_terminal_logins' );
    tm_json( tm_result( $db, $tid ) );
}

/* ==================================================================================
 *  Session-/Zugriffs-Tracking (Sitzungen, Fehl-Logins, Verlauf, Land/Whois)
 * ================================================================================== */
if ( function_exists( 'pacim_ts_ensure_tables' ) ) pacim_ts_ensure_tables( $db );

/** Alle Sitzungs-IDs derselben (Terminal, Login, IP, Gerät, Status)-Gruppe wie die übergebene Sitzung. */
function tm_group_ids( $db, $sid ) {
    $s = $db->rawQueryOne( "SELECT ts_terminal, ts_login, ts_ip, ts_ua, ts_ok FROM pacim_terminal_sessions WHERE ts_id = ?", array( (int) $sid ) );
    if ( ! $s ) return array();
    $rows = (array) $db->rawQuery(
        "SELECT ts_id FROM pacim_terminal_sessions WHERE ts_terminal = ? AND ts_login = ? AND ts_ip = ? AND ts_ua = ? AND ts_ok = ?",
        array( (int) $s['ts_terminal'], (int) $s['ts_login'], (string) $s['ts_ip'], (string) $s['ts_ua'], (int) $s['ts_ok'] ) );
    $ids = array(); foreach ( $rows as $r ) $ids[] = (int) $r['ts_id'];
    return $ids;
}

/* ---- Liste der Sitzungen (gruppiert nach Terminal · Login · IP · Gerät) + Fehlversuche ---- */
if ( $action === 'sessions' ) {
    $tid   = (int) ( $_GET['terminal'] ?? 0 );
    $only  = (string) ( $_GET['filter'] ?? '' );  // '' | 'ok' | 'fail'
    $limit = max( 1, min( 500, (int) ( $_GET['limit'] ?? 200 ) ) );
    $where = array(); $args = array();
    if ( $tid > 0 ) { $where[] = 's.ts_terminal = ?'; $args[] = $tid; }
    if ( $only === 'ok' )   $where[] = 's.ts_ok = 1';
    if ( $only === 'fail' ) $where[] = 's.ts_ok = 0';
    $wsql = $where ? ( 'WHERE ' . implode( ' AND ', $where ) ) : '';
    // Gleiche IP + gleicher Kontext (Terminal/Login/Gerät/Status) → EIN Eintrag, Aktivität zusammengefasst.
    $rows = (array) $db->rawQuery(
        "SELECT MAX(s.ts_id) AS ts_id, s.ts_terminal, s.ts_login, s.ts_ip, s.ts_ua, s.ts_ok,
                MAX(t.terminal_label) AS terminal_label, MAX(s.ts_name) AS ts_name,
                MIN(s.ts_started) AS started, MAX(s.ts_last_seen) AS last_seen,
                SUM(s.ts_events) AS events, COUNT(*) AS sessions,
                MAX(NULLIF(s.ts_country,'')) AS ts_country, MAX(NULLIF(s.ts_geo,'')) AS ts_geo
           FROM pacim_terminal_sessions s
           LEFT JOIN pacim_terminals t ON t.terminal_id = s.ts_terminal
           $wsql
          GROUP BY s.ts_terminal, s.ts_login, s.ts_ip, s.ts_ua, s.ts_ok
          ORDER BY last_seen DESC LIMIT $limit", $args );

    // Fehlende Länder lazy nachziehen – je eindeutiger IP nur einmal, max. 15 externe Abfragen pro Aufruf,
    // Ergebnis für alle Sitzungen dieser IP cachen.
    $lookups = 0; $ipCache = array();
    foreach ( $rows as &$r ) {
        if ( trim( (string) $r['ts_country'] ) === '' && trim( (string) $r['ts_geo'] ) === '' ) {
            $ip = (string) $r['ts_ip']; $g = null;
            if ( isset( $ipCache[ $ip ] ) ) $g = $ipCache[ $ip ];
            elseif ( $lookups < 15 ) { $lookups++; $g = pacim_ts_geo( $ip ); $ipCache[ $ip ] = $g; }
            if ( $g !== null ) {
                $geo = $g['geo'] !== '' ? $g['geo'] : '—';
                $db->rawQuery( "UPDATE pacim_terminal_sessions SET ts_country = ?, ts_geo = ? WHERE ts_ip = ? AND ts_country = '' AND ts_geo = ''", array( $g['cc'], $geo, $ip ) );
                $r['ts_country'] = $g['cc']; $r['ts_geo'] = $geo;
            }
        }
    }
    unset( $r );

    $items = array();
    foreach ( $rows as $r ) {
        $items[] = array(
            'id'        => (int) $r['ts_id'],
            'terminal'  => (int) $r['ts_terminal'],
            'terminal_label' => (string) ( $r['terminal_label'] ?? '' ),
            'name'      => (string) $r['ts_name'],
            'ok'        => (int) $r['ts_ok'],
            'ip'        => (string) $r['ts_ip'],
            'ua'        => (string) $r['ts_ua'],
            'country'   => strtoupper( (string) $r['ts_country'] ),
            'geo'       => (string) $r['ts_geo'],
            'started'   => (string) $r['started'],
            'last_seen' => (string) $r['last_seen'],
            'events'    => (int) $r['events'],
            'sessions'  => (int) $r['sessions'],
        );
    }
    tm_json( array( 'ok' => true, 'sessions' => $items ) );
}

/* ---- Einzelne Sitzung: Metadaten + Kennzahlen (Statistik/Diagramm). Der Verlauf kommt via session_events. ---- */
if ( $action === 'session' ) {
    $sid = (int) ( $_GET['id'] ?? 0 );
    $s = $db->rawQueryOne(
        "SELECT s.*, t.terminal_label FROM pacim_terminal_sessions s
           LEFT JOIN pacim_terminals t ON t.terminal_id = s.ts_terminal WHERE s.ts_id = ?", array( $sid ) );
    if ( ! $s ) tm_fail( 'Sitzung nicht gefunden.' );

    // Gesamte Gruppe (gleiche IP + gleicher Kontext) → zusammengefasste Metadaten & Verlauf.
    $ids = tm_group_ids( $db, $sid ); if ( ! $ids ) $ids = array( $sid );
    $in = implode( ',', $ids );
    $meta = $db->rawQueryOne( "SELECT MIN(ts_started) started, MAX(ts_last_seen) last_seen, SUM(ts_events) events, COUNT(*) sessions FROM pacim_terminal_sessions WHERE ts_id IN ($in)" );

    // Land/Ort aus der Gruppe (irgendeine gesetzte), sonst lazy auflösen und für die ganze IP cachen.
    $geoRow = $db->rawQueryOne( "SELECT MAX(NULLIF(ts_country,'')) cc, MAX(NULLIF(ts_geo,'')) geo FROM pacim_terminal_sessions WHERE ts_id IN ($in)" );
    $cc = (string) ( $geoRow['cc'] ?? '' ); $geo = (string) ( $geoRow['geo'] ?? '' );
    if ( $cc === '' && $geo === '' ) {
        $g = pacim_ts_geo( (string) $s['ts_ip'] ); $cc = $g['cc']; $geo = $g['geo'] !== '' ? $g['geo'] : '—';
        $db->rawQuery( "UPDATE pacim_terminal_sessions SET ts_country = ?, ts_geo = ? WHERE ts_ip = ? AND ts_country = '' AND ts_geo = ''", array( $cc, $geo, (string) $s['ts_ip'] ) );
    }

    // Roh-Aggregat (Tag × Aktion × Stunde) über ALLE Sitzungen der Gruppe – der Client leitet daraus
    // Kennzahlen ab und filtert nach Tag (Statistiken/Diagramm).
    $agg = array();
    foreach ( (array) $db->rawQuery( "SELECT DATE(te_at) d, te_type, HOUR(te_at) h, COUNT(*) c FROM pacim_terminal_events WHERE te_session IN ($in) GROUP BY DATE(te_at), te_type, HOUR(te_at)" ) as $r ) {
        $agg[] = array( 'date' => (string) $r['d'], 'type' => (string) $r['te_type'], 'hour' => (int) $r['h'], 'count' => (int) $r['c'] );
    }
    $labels = array();
    foreach ( (array) $db->rawQuery( "SELECT DISTINCT te_type FROM pacim_terminal_events WHERE te_session IN ($in)" ) as $r ) {
        $labels[ (string) $r['te_type'] ] = function_exists( 'pacim_ts_event_label' ) ? pacim_ts_event_label( $r['te_type'] ) : (string) $r['te_type'];
    }

    tm_json( array( 'ok' => true, 'session' => array(
        'id'        => (int) $s['ts_id'],
        'terminal_label' => (string) ( $s['terminal_label'] ?? '' ),
        'name'      => (string) $s['ts_name'],
        'ok'        => (int) $s['ts_ok'],
        'ip'        => (string) $s['ts_ip'],
        'ua'        => (string) $s['ts_ua'],
        'country'   => strtoupper( $cc ),
        'geo'       => $geo,
        'started'   => (string) ( $meta['started'] ?? $s['ts_started'] ),
        'last_seen' => (string) ( $meta['last_seen'] ?? $s['ts_last_seen'] ),
        'events'    => (int) ( $meta['events'] ?? 0 ),
        'sessions'  => (int) ( $meta['sessions'] ?? 1 ),
    ), 'agg' => $agg, 'labels' => $labels ) );
}

/* ---- Verlauf einer Sitzung: gefiltert (Aktion/Zeitraum) + paginiert ---- */
if ( $action === 'session_events' ) {
    $sid  = (int) ( $_GET['id'] ?? 0 );
    $gids = tm_group_ids( $db, $sid );
    if ( ! $gids ) tm_fail( 'Sitzung nicht gefunden.' );
    $gin = implode( ',', $gids );
    $type = trim( (string) ( $_GET['type'] ?? '' ) );
    $from = trim( (string) ( $_GET['from'] ?? '' ) );
    $to   = trim( (string) ( $_GET['to'] ?? '' ) );
    $per  = in_array( (int) ( $_GET['per'] ?? 20 ), array( 20, 50, 100, 200 ), true ) ? (int) $_GET['per'] : 20;
    $page = max( 1, (int) ( $_GET['page'] ?? 1 ) );

    $w = array( "e.te_session IN ($gin)" ); $a = array();
    if ( $type !== '' ) { $w[] = 'e.te_type = ?'; $a[] = $type; }
    if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $from ) ) { $w[] = 'e.te_at >= ?'; $a[] = $from . ' 00:00:00'; }
    if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $to ) )   { $w[] = 'e.te_at < ?';  $a[] = date( 'Y-m-d 00:00:00', strtotime( $to . ' +1 day' ) ); }
    $wsql = implode( ' AND ', $w );

    $tot = $db->rawQueryOne( "SELECT COUNT(*) c FROM pacim_terminal_events e WHERE $wsql", $a );
    $total = $tot ? (int) $tot['c'] : 0;
    $pages = max( 1, (int) ceil( $total / $per ) );
    if ( $page > $pages ) $page = $pages;
    $off = ( $page - 1 ) * $per;

    $rows = (array) $db->rawQuery(
        "SELECT e.*, b.booking_no, license_plate(b.booking_serial) AS plate,
                c.customer_lastname, c.customer_firstname, c.customer_name AS company
           FROM pacim_terminal_events e
           LEFT JOIN pacim_booking  b ON b.booking_id  = e.te_booking
           LEFT JOIN pacim_customer c ON c.customer_id = b.booking_customer
          WHERE $wsql ORDER BY e.te_at DESC, e.te_id DESC LIMIT $per OFFSET $off", $a );
    $events = array();
    foreach ( $rows as $e ) {
        $ln = trim( (string) ( $e['customer_lastname'] ?? '' ) ); $fn = trim( (string) ( $e['customer_firstname'] ?? '' ) );
        $cust = ( $ln !== '' || $fn !== '' ) ? trim( $ln . ( $fn !== '' ? ', ' . $fn : '' ) ) : trim( (string) ( $e['company'] ?? '' ) );
        $events[] = array(
            'at'      => (string) $e['te_at'],
            'type'    => (string) $e['te_type'],
            'label'   => function_exists( 'pacim_ts_event_label' ) ? pacim_ts_event_label( $e['te_type'] ) : (string) $e['te_type'],
            'booking' => (int) $e['te_booking'],
            'invoice' => (int) $e['te_invoice'],
            'booking_no' => (string) ( $e['booking_no'] ?? '' ),
            'plate'   => trim( (string) ( $e['plate'] ?? '' ) ),
            'customer'=> $cust,
            'detail'  => (string) $e['te_detail'],
            'link'    => ( (int) $e['te_invoice'] > 0 ) ? ( SITE_URL . '/booking/view/?invoice_id=' . (int) $e['te_invoice'] ) : '',
        );
    }
    tm_json( array( 'ok' => true, 'events' => $events, 'total' => $total, 'page' => $page, 'per' => $per, 'pages' => $pages ) );
}

/* ---- Whois-/RIR-Abfrage zu einer IP ---- */
if ( $action === 'whois' ) {
    $ip = trim( (string) ( $_GET['ip'] ?? '' ) );
    tm_json( pacim_ts_whois( $ip ) );
}

/* ---- Sitzungen löschen (einzeln / Fehl-Logins / alle) ---- */
if ( $action === 'sessions_delete' ) {
    $sid   = (int) ( $_POST['id'] ?? 0 );
    $scope = (string) ( $_POST['scope'] ?? '' );  // '' (einzeln) | 'fails' | 'all'
    if ( $scope === 'all' ) {
        $db->rawQuery( "DELETE FROM pacim_terminal_events" );
        $db->rawQuery( "DELETE FROM pacim_terminal_sessions" );
    } elseif ( $scope === 'fails' ) {
        $db->rawQuery( "DELETE FROM pacim_terminal_sessions WHERE ts_ok = 0" );
    } elseif ( $sid > 0 ) {
        // Ganze Gruppe (gleiche IP + Kontext) löschen, wie in der Liste dargestellt.
        $gids = tm_group_ids( $db, $sid ); if ( ! $gids ) $gids = array( $sid );
        $gin = implode( ',', $gids );
        $db->rawQuery( "DELETE FROM pacim_terminal_events WHERE te_session IN ($gin)" );
        $db->rawQuery( "DELETE FROM pacim_terminal_sessions WHERE ts_id IN ($gin)" );
    } else { tm_fail( 'Nichts zu löschen.' ); }
    tm_json( array( 'ok' => true ) );
}

tm_fail( 'Unbekannte Aktion.' );

Youez - 2016 - github.com/yon3zu
LinuXploit