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/accounting-api.php
<?php
/**
 * accounting-api.php – Monatsabrechnung: Erstellen (mit Fortschritt), Status, ZIP-Download.
 *
 *  action=create  POST year,month   -> erzeugt PDFs + Excel in datas/month_reports/{year}-{month}/,
 *                                       schreibt laufend _status.json; gibt am Ende JSON zurück.
 *  action=status  GET  year,month   -> { ok, status:{phase,total,done,percent,message,finished,error} }
 *  action=zip     GET  year,month[,dl] -> streamt das Monatsverzeichnis als ZIP
 *
 * (Google-Drive-Upload folgt in Phase 2.)
 */
require_once( __DIR__ . '/includes/config.inc.php' );
@ini_set( 'display_errors', '0' );
error_reporting( 0 );

if ( ! isset( $_SESSION['user'] ) || $_SESSION['user'] != LOGIN_USER ) {
    header( 'Content-Type: application/json; charset=utf-8' );
    http_response_code( 403 );
    echo json_encode( array( 'ok' => false, 'error' => 'unauthorized' ) );
    exit();
}

// Session-Lock früh freigeben, damit Status-Polling NICHT durch die lange create-Anfrage blockiert wird.
session_write_close();

$action = isset( $_GET['action'] ) ? $_GET['action'] : ( isset( $_POST['action'] ) ? $_POST['action'] : '' );

function ac_year( $v )  { return ( is_string( $v ) && preg_match( '/^\d{4}$/', $v ) ) ? $v : null; }
function ac_month( $v ) { return ( is_string( $v ) && preg_match( '/^(0[1-9]|1[0-2])$/', $v ) ) ? $v : null; }
function ac_json( $arr ) { while ( ob_get_level() > 0 ) ob_end_clean(); header( 'Content-Type: application/json; charset=utf-8' ); echo json_encode( $arr ); exit(); }
function ac_dir( $year, $month ) { return PATH_SYSTEM . '/datas/month_reports/' . $year . '-' . $month . '/'; }
function ac_statusfile( $year, $month ) { return ac_dir( $year, $month ) . '_status.json'; }

/* ====================== STATUS ====================== */
if ( $action === 'status' ) {
    $year  = ac_year( isset( $_GET['year'] ) ? $_GET['year'] : '' );
    $month = ac_month( isset( $_GET['month'] ) ? $_GET['month'] : '' );
    if ( ! $year || ! $month ) ac_json( array( 'ok' => false, 'error' => 'bad_params' ) );

    $sf = ac_statusfile( $year, $month );
    if ( ! is_file( $sf ) ) {
        ac_json( array( 'ok' => true, 'status' => array( 'phase' => 'idle', 'percent' => 0, 'message' => '', 'finished' => false, 'error' => false ) ) );
    }
    $st = json_decode( file_get_contents( $sf ), true );
    if ( ! is_array( $st ) ) $st = array( 'phase' => 'idle', 'percent' => 0, 'finished' => false, 'error' => false );
    ac_json( array( 'ok' => true, 'status' => $st ) );
}

/* ====================== CREATE (mit Fortschritt) ====================== */
if ( $action === 'create' ) {
    $year  = ac_year( isset( $_POST['year'] ) ? $_POST['year'] : '' );
    $month = ac_month( isset( $_POST['month'] ) ? $_POST['month'] : '' );
    if ( ! $year || ! $month ) ac_json( array( 'ok' => false, 'error' => 'bad_params' ) );

    @set_time_limit( 0 );
    @ignore_user_abort( true );

    $dir = ac_dir( $year, $month );
    if ( ! is_dir( $dir ) ) @mkdir( $dir, 0777, true );
    $sf = ac_statusfile( $year, $month );

    // Startstatus sofort schreiben (Frontend pollt bereits)
    @file_put_contents( $sf, json_encode( array( 'phase' => 'start', 'total' => 0, 'done' => 0, 'percent' => 0, 'message' => 'Wird gestartet …', 'finished' => false, 'error' => false, 'updated' => date( 'c' ) ) ) );

    require_once( PATH_SYSTEM . '/includes/accounting.create.php' );
    global $oData, $oPDF;

    try {
        $count = accounting_create_month( $oData, $oPDF, $year, $month, $sf );
        // Monat als "erstellt" in der DB vermerken (Flag für die Übersicht).
        if ( class_exists( 'settings' ) ) {
            settings::set( 'accounting_created:' . $year . '-' . $month, date( 'c' ) );
        }
        ac_json( array( 'ok' => true, 'count' => (int) $count ) );
    } catch ( Throwable $e ) {
        @file_put_contents( $sf, json_encode( array( 'phase' => 'error', 'percent' => 0, 'message' => 'Fehler bei der Erstellung.', 'finished' => true, 'error' => true, 'detail' => $e->getMessage(), 'updated' => date( 'c' ) ) ) );
        ac_json( array( 'ok' => false, 'error' => 'create_failed' ) );
    }
}

/* ====================== GOOGLE-DRIVE-Upload ====================== */
if ( $action === 'drive' ) {
    $year  = ac_year( isset( $_POST['year'] ) ? $_POST['year'] : '' );
    $month = ac_month( isset( $_POST['month'] ) ? $_POST['month'] : '' );
    if ( ! $year || ! $month ) ac_json( array( 'ok' => false, 'error' => 'bad_params' ) );

    $dir = ac_dir( $year, $month );
    if ( ! is_dir( $dir ) ) ac_json( array( 'ok' => false, 'error' => 'not_created' ) );
    $sf = ac_statusfile( $year, $month );

    // Startstatus sofort setzen, damit das Polling unmittelbar etwas sieht.
    @file_put_contents( $sf, json_encode( array( 'phase' => 'drive', 'total' => 0, 'done' => 0, 'percent' => 1, 'message' => 'Wird gestartet …', 'finished' => false, 'error' => false, 'updated' => date( 'c' ) ) ) );

    // Upload als entkoppelten CLI-Prozess starten -> kein FPM-Zeitlimit (php_admin max_execution_time=300),
    // kein Webserver-Timeout/-Retry. Fortschritt/Abschluss kommen über das Status-Polling.
    $php    = is_executable( '/usr/bin/php7.3' ) ? '/usr/bin/php7.3' : 'php';
    $script = PATH_SYSTEM . '/includes/accounting.drive.cli.php';
    $cmd    = 'nohup ' . $php . ' ' . escapeshellarg( $script ) . ' ' . escapeshellarg( $year ) . ' ' . escapeshellarg( $month ) . ' >/dev/null 2>&1 &';
    @exec( $cmd );

    ac_json( array( 'ok' => true, 'started' => true ) );
}

/* ====================== ZIP-Download ====================== */
if ( $action === 'zip' ) {
    $year  = ac_year( isset( $_GET['year'] ) ? $_GET['year'] : '' );
    $month = ac_month( isset( $_GET['month'] ) ? $_GET['month'] : '' );
    if ( ! $year || ! $month ) { while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 400 ); echo 'bad request'; exit(); }

    $dir = ac_dir( $year, $month );
    if ( ! is_dir( $dir ) ) { while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 404 ); echo 'not found'; exit(); }

    $files = array();
    foreach ( (array) glob( $dir . '*' ) as $f ) {
        if ( ! is_file( $f ) ) continue;
        $base = basename( $f );
        if ( strpos( $base, '_status' ) === 0 ) continue; // interne Statusdatei nicht mitpacken
        $files[] = $f;
    }
    if ( ! $files ) { while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 404 ); echo 'leer'; exit(); }

    $tmp = tempnam( sys_get_temp_dir(), 'pacimzip' );
    $zip = new ZipArchive();
    if ( $zip->open( $tmp, ZipArchive::CREATE | ZipArchive::OVERWRITE ) !== true ) { @unlink( $tmp ); while ( ob_get_level() > 0 ) ob_end_clean(); http_response_code( 500 ); echo 'zip error'; exit(); }
    foreach ( $files as $f ) $zip->addFile( $f, basename( $f ) );
    $zip->close();

    $down = $year . '-' . $month . '-Monatsabrechnung.zip';
    while ( ob_get_level() > 0 ) ob_end_clean();
    header( 'Content-Type: application/zip' );
    header( 'Content-Disposition: attachment; filename="' . $down . '"' );
    header( 'Content-Length: ' . filesize( $tmp ) );
    header( 'X-Content-Type-Options: nosniff' );
    readfile( $tmp );
    @unlink( $tmp );
    exit();
}

http_response_code( 400 );
ac_json( array( 'ok' => false, 'error' => 'unknown_action' ) );

Youez - 2016 - github.com/yon3zu
LinuXploit