shop-old/modules/admin2000.php
2026-04-20 01:03:43 +02:00

400 lines
16 KiB
PHP

<?php
/**
* Admin2000 - Modernes Admin-System
*
* Komplett neues, paralleles Admin-System mit:
* - Modernem CSS Layout
* - Responsive Design
* - Sauberer Code-Struktur
* - Keine Inline-Styles
*
* @package Admin2000
* @author Claude & Team
* @version 1.0.0
*/
class admin2000 {
private $base_object;
private $layout_object;
function __construct($base_object, $layout_object) {
$this->base_object = $base_object;
$this->layout_object = $layout_object;
}
function run() {
$debug_file = './admin2000_debug.log';
file_put_contents($debug_file, "\n=== RUN() START " . date('Y-m-d H:i:s') . " ===\n", FILE_APPEND);
file_put_contents($debug_file, "REQUEST_METHOD: " . $_SERVER['REQUEST_METHOD'] . "\n", FILE_APPEND);
file_put_contents($debug_file, "GET: " . print_r($_GET, true) . "\n", FILE_APPEND);
file_put_contents($debug_file, "POST keys: " . print_r(array_keys($_POST), true) . "\n", FILE_APPEND);
// Get section and page from URL
$section = isset($_GET['section']) ? $_GET['section'] : 'stammdaten';
$page = isset($_GET['page']) ? $_GET['page'] : 'kunden';
$action = isset($_GET['action']) ? $_GET['action'] : '';
file_put_contents($debug_file, "Section: $section, Page: $page, Action: $action\n", FILE_APPEND);
file_put_contents($debug_file, "POST action: " . (isset($_POST['action']) ? $_POST['action'] : 'NONE') . "\n", FILE_APPEND);
// Handle POST save action
if (isset($_POST['action']) && $_POST['action'] == 'save' && $page == 'kunden_editor') {
file_put_contents($debug_file, "Routing to save_customer()\n", FILE_APPEND);
return $this->save_customer();
}
// Handle AJAX requests (return partial HTML only)
if ($action == 'get_list_items') {
return $this->get_list_items($section, $page);
}
// Build navigation data
$navigation = $this->build_navigation($section, $page);
$this->layout_object->assign('admin2000_nav', $navigation);
$this->layout_object->assign('admin2000_section', $section);
$this->layout_object->assign('admin2000_page', $page);
// Pass admin user data to template
$this->layout_object->assign('admin_user', $this->base_object->customer);
// Load page content
$content = $this->load_page_content($section, $page);
$this->layout_object->assign('admin2000_content', $content);
// Load FULL standalone HTML layout (not wrapped in main.tpl)
return $this->layout_object->fetch('admin2000_layout.tpl');
}
/**
* Build navigation structure
*/
private function build_navigation($active_section, $active_page) {
$nav = array(
'stammdaten' => array(
'title' => 'Stammdaten',
'icon' => '📊',
'pages' => array(
'kunden' => array(
'title' => 'Kunden',
'url' => './index.php?admin_modul=admin2000&section=stammdaten&page=kunden',
'icon' => '👥',
'active' => ($active_section == 'stammdaten' && $active_page == 'kunden')
),
'artikel' => array(
'title' => 'Artikel',
'url' => './index.php?admin_modul=admin2000&section=stammdaten&page=artikel',
'icon' => '📦',
'active' => ($active_section == 'stammdaten' && $active_page == 'artikel')
),
'lieferanten' => array(
'title' => 'Lieferanten',
'url' => './index.php?admin_modul=admin2000&section=stammdaten&page=lieferanten',
'icon' => '🚚',
'active' => ($active_section == 'stammdaten' && $active_page == 'lieferanten')
)
)
)
);
return $nav;
}
/**
* Load page content based on section and page
*/
private function load_page_content($section, $page) {
// Load data for specific pages
if ($section == 'stammdaten' && $page == 'kunden') {
$this->load_customer_data();
} elseif ($section == 'stammdaten' && $page == 'kunden_editor') {
$this->load_customer_editor_data();
}
// Build template path
$template_file = "admin2000/{$section}_{$page}.tpl";
// Check if template exists
$template_path = ROOT_DIR . "/themes/admin/templates/{$template_file}";
if (!file_exists($template_path)) {
// Return placeholder if template doesn't exist yet
return $this->get_placeholder_content($section, $page);
}
// Load and return template
return $this->layout_object->fetch($template_file);
}
/**
* Get placeholder content for pages that don't exist yet
*/
private function get_placeholder_content($section, $page) {
return "
<div style='padding: 40px; text-align: center; background: #f8f9fa; border-radius: 8px; margin: 20px;'>
<h2 style='color: #333; margin-bottom: 20px;'>🚧 In Entwicklung</h2>
<p style='color: #666; font-size: 16px; margin-bottom: 30px;'>
Diese Seite wird gerade entwickelt.
</p>
<div style='background: white; padding: 20px; border-radius: 6px; display: inline-block;'>
<strong>Section:</strong> {$section}<br>
<strong>Page:</strong> {$page}<br>
<strong>Template:</strong> admin2000/{$section}_{$page}.tpl
</div>
</div>
";
}
/**
* Load customer data for the list
*/
private function load_customer_data() {
include_once './core/customer.class.php';
$customer = new Customer($this->base_object);
// Pass table config to template
$table_data = $customer->list_table_config;
$table_data['list_filter'] = $customer->get_filter();
// Get customer statistics
$stats = $this->get_customer_stats();
$this->layout_object->assign('table_data', $table_data);
$this->layout_object->assign('customer_stats', $stats);
}
/**
* Get customer statistics for dashboard cards
*/
private function get_customer_stats() {
$db = $this->base_object->db;
$stats = array();
// Total customers
$sql = "SELECT COUNT(*) as total FROM customers";
$result = $db->query($sql);
$row = $result->fetch_assoc();
$stats['total'] = $row['total'];
// Active customers (locked = 0 means active)
$sql = "SELECT COUNT(*) as active FROM customers WHERE locked = 0";
$result = $db->query($sql);
$row = $result->fetch_assoc();
$stats['active'] = $row['active'];
// Locked/Disabled customers
$sql = "SELECT COUNT(*) as locked FROM customers WHERE locked = 1";
$result = $db->query($sql);
$row = $result->fetch_assoc();
$stats['locked'] = $row['locked'];
// New customers in last 30 days
$sql = "SELECT COUNT(*) as new_30days FROM customers WHERE registration_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)";
$result = $db->query($sql);
$row = $result->fetch_assoc();
$stats['new_30days'] = $row['new_30days'];
return $stats;
}
/**
* Load customer editor data - WITH INJECTION PROTECTION!
*/
private function load_customer_editor_data() {
include_once './core/customer.class.php';
include_once './core/customeraddress.class.php';
include_once './core/order.class.php';
// SECURITY: Validate and sanitize customer ID
$customer_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
if ($customer_id <= 0) {
$this->layout_object->assign('error', 'Ungültige Kunden-ID');
return;
}
$customer = new Customer($this->base_object);
// Check if customer exists
if (!Customer::has_id($customer_id)) {
$this->layout_object->assign('error', 'Kunde nicht gefunden');
return;
}
// Load customer data - using get_data() for FULL legacy compatibility
// (includes group_name, show_tax via LEFT JOIN customer_groups)
$customer_data = $customer->get_data($customer_id);
// Convert OBJECT to ARRAY for Smarty template compatibility
$customer_data = (array) $customer_data;
// Load customer addresses
$customer_address_object = new CustomerAddress($this->base_object);
$customer_addresses = $customer_address_object->get_data_by_customer_id($customer_id);
// Convert addresses to array if needed
if ($customer_addresses && is_array($customer_addresses)) {
$addresses_array = array();
foreach ($customer_addresses as $addr) {
$addresses_array[] = (array) $addr;
}
$customer_addresses = $addresses_array;
}
// Load customer orders (Bestellungen/Rechnungen)
$orders = OrderHelper::get_all_customer_orders($customer_id);
// Convert orders to array if needed
if ($orders && is_array($orders)) {
$orders_array = array();
foreach ($orders as $order) {
$orders_array[] = (array) $order;
}
$orders = $orders_array;
}
// Get form field configuration from customer class
$form_config = $customer->list_table_config['edit_fields'];
// Load select options for dropdowns
$select_values = array();
foreach ($form_config as $field) {
if (isset($field['values']) && is_string($field['values'])) {
// Call the function to get values (e.g. customer_group_values())
$select_values[$field['db_field']] = $customer->{$field['values']}();
}
}
// Check if save was successful
$save_success = isset($_GET['saved']) && $_GET['saved'] == '1';
// Pass to template
$this->layout_object->assign('customer_id', $customer_id);
$this->layout_object->assign('customer_data', $customer_data);
$this->layout_object->assign('customer_addresses', $customer_addresses);
$this->layout_object->assign('orders', $orders);
$this->layout_object->assign('form_config', $form_config);
$this->layout_object->assign('select_values', $select_values);
$this->layout_object->assign('save_success', $save_success);
}
/**
* Save customer data - WITH INJECTION PROTECTION!
*/
private function save_customer() {
// DEBUG: Write to file
$debug_file = './admin2000_debug.log';
file_put_contents($debug_file, "=== SAVE_CUSTOMER START " . date('Y-m-d H:i:s') . " ===\n", FILE_APPEND);
file_put_contents($debug_file, "POST data: " . print_r($_POST, true) . "\n", FILE_APPEND);
include_once './core/customer.class.php';
// SECURITY: Validate customer ID
$customer_id = isset($_POST['customer_id']) ? intval($_POST['customer_id']) : 0;
file_put_contents($debug_file, "Customer ID: " . $customer_id . "\n", FILE_APPEND);
if ($customer_id <= 0) {
file_put_contents($debug_file, "ERROR: Invalid customer ID\n", FILE_APPEND);
die('Ungültige Kunden-ID');
}
$customer = new Customer($this->base_object);
file_put_contents($debug_file, "Customer object created\n", FILE_APPEND);
// Check if customer exists
if (!Customer::has_id($customer_id)) {
file_put_contents($debug_file, "ERROR: Customer not found\n", FILE_APPEND);
die('Kunde nicht gefunden');
}
file_put_contents($debug_file, "Customer exists check passed\n", FILE_APPEND);
// SECURITY: Sanitize all input data
// Legacy uses 'customer_field' not 'customer_data'!
$customer_data = isset($_POST['customer_field']) ? $_POST['customer_field'] : array();
file_put_contents($debug_file, "customer_field data: " . print_r($customer_data, true) . "\n", FILE_APPEND);
$sanitized_data = array();
foreach ($customer_data as $key => $value) {
// Only allow alphanumeric field names (prevent injection)
if (preg_match('/^[a-zA-Z0-9_]+$/', $key)) {
// CRITICAL: Don't send empty password (would create md5('') hash!)
if ($key === 'pass' && trim($value) === '') {
continue;
}
// Sanitize value based on type
if (is_array($value)) {
$sanitized_data[$key] = array_map('strip_tags', $value);
} else {
$sanitized_data[$key] = strip_tags($value);
}
}
}
// Add customer ID to data
$sanitized_data['id'] = $customer_id;
file_put_contents($debug_file, "Sanitized data: " . print_r($sanitized_data, true) . "\n", FILE_APPEND);
// Save using legacy customer class (has its own security)
file_put_contents($debug_file, "Calling customer->save()\n", FILE_APPEND);
$result = $customer->save($sanitized_data, $customer_id);
file_put_contents($debug_file, "Save result: " . ($result ? 'SUCCESS' : 'FAILED') . "\n", FILE_APPEND);
if ($result) {
// Redirect back to editor with success message
file_put_contents($debug_file, "Redirecting to editor\n", FILE_APPEND);
header('Location: ./index.php?admin_modul=admin2000&section=stammdaten&page=kunden_editor&id=' . $customer_id . '&saved=1');
exit();
} else {
file_put_contents($debug_file, "ERROR: Save failed\n", FILE_APPEND);
die('Fehler beim Speichern der Daten');
}
}
/**
* AJAX handler to get list items
*/
private function get_list_items($section, $page) {
if ($section == 'stammdaten' && $page == 'kunden') {
include_once './core/customer.class.php';
try {
$customer = new Customer($this->base_object);
// Get settings from request
$max_list_items = isset($_GET['max_list_items']) ? (int)$_GET['max_list_items'] : 20;
$actual_page = isset($_GET['actual_page']) ? (int)$_GET['actual_page'] : 1;
$sort_item = isset($_GET['sort_item']) ? $_GET['sort_item'] : 'number';
$sort_direction = isset($_GET['sort_direction']) ? $_GET['sort_direction'] : 'up';
$search_string = isset($_GET['search_string']) ? $_GET['search_string'] : '';
$list_filter = isset($_GET['list_filter']) && is_array($_GET['list_filter']) ? $_GET['list_filter'] : array();
$setting = array(
'max_list_items' => $max_list_items,
'actual_page' => $actual_page,
'sort_item' => $sort_item,
'sort_direction' => $sort_direction,
'search_string' => $search_string,
'list_filter' => $list_filter,
'data_format' => 1
);
$list_data = $customer->get_list_items($setting);
$list_data['list_table_config'] = $customer->list_table_config;
$this->layout_object->assign('list_data', $list_data);
return $this->layout_object->fetch('admin2000_list_items.tpl');
} catch (Exception $e) {
// Error handling
$error_html = '<tr><td colspan="100" style="text-align: center; padding: 40px; color: #e74c3c;">';
$error_html .= '<strong>Fehler beim Laden der Daten</strong><br>';
$error_html .= htmlspecialchars($e->getMessage());
$error_html .= '</td></tr>';
return $error_html;
}
}
return json_encode(array('error' => 'Unknown page'));
}
}