false, 'message' => 'Name darf nicht leer sein.']); exit; } $sql = "INSERT INTO zones (user_id, name) VALUES (?, ?)"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("is", $user_id, trim($_POST['name'])); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'edit_zone': if (empty(trim($_POST['name'])) || empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Unvollständige Daten.']); exit; } $sql = "UPDATE zones SET name = ? WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("sii", trim($_POST['name']), $_POST['id'], $user_id); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'delete_zone': if (empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Fehlende ID.']); exit; } $sql = "DELETE FROM zones WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $_POST['id'], $user_id); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'add_container': if (empty(trim($_POST['name'])) || empty($_POST['zone_id'])) { echo json_encode(['success' => false, 'message' => 'Name und Zone sind Pflichtfelder.']); exit; } $sql = "INSERT INTO containers (user_id, name, zone_id) VALUES (?, ?, ?)"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("isi", $user_id, trim($_POST['name']), $_POST['zone_id']); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'edit_container': if (empty(trim($_POST['name'])) || empty($_POST['zone_id']) || empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Alle Felder sind Pflicht.']); exit; } $sql = "UPDATE containers SET name = ?, zone_id = ? WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("siii", trim($_POST['name']), $_POST['zone_id'], $_POST['id'], $user_id); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'delete_container': if (empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Fehlende ID.']); exit; } $sql = "DELETE FROM containers WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $_POST['id'], $user_id); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'add_seed': if (empty(trim($_POST['strain_name']))) { echo json_encode(['success' => false, 'message' => 'Sortenname ist ein Pflichtfeld.']); exit; } $sql = "INSERT INTO seeds (user_id, strain_name, internal_name, info_url, ratio_sativa, is_autoflower, stock_count, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; if ($stmt = $mysqli->prepare($sql)) { $is_autoflower = isset($_POST['is_autoflower']) ? 1 : 0; $stmt->bind_param("isssiiis", $user_id, $_POST['strain_name'], $_POST['internal_name'], $_POST['info_url'], $_POST['ratio_sativa'], $is_autoflower, $_POST['stock_count'], $_POST['description']); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'edit_seed': if (empty(trim($_POST['strain_name'])) || empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'ID und Sortenname sind Pflichtfelder.']); exit; } $sql = "UPDATE seeds SET strain_name = ?, internal_name = ?, info_url = ?, ratio_sativa = ?, is_autoflower = ?, stock_count = ?, description = ? WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $is_autoflower = isset($_POST['is_autoflower']) ? 1 : 0; $stmt->bind_param("sssiiisii", $_POST['strain_name'], $_POST['internal_name'], $_POST['info_url'], $_POST['ratio_sativa'], $is_autoflower, $_POST['stock_count'], $_POST['description'], $_POST['id'], $user_id); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'delete_seed': if (empty($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Fehlende ID.']); exit; } $sql = "DELETE FROM seeds WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $_POST['id'], $user_id); if ($stmt->execute()) { echo json_encode(['success' => true]); } } break; case 'get_containers_by_zone': if (empty($_GET['zone_id']) || !is_numeric($_GET['zone_id'])) { echo json_encode(['success' => false, 'message' => 'Keine oder ungültige Zone ID.']); exit; } $zone_id = $_GET['zone_id']; $containers = []; $sql = "SELECT id, name FROM containers WHERE user_id = ? AND zone_id = ? AND id NOT IN (SELECT container_id FROM plants WHERE status = 'Eingepflanzt')"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $user_id, $zone_id); $stmt->execute(); $result = $stmt->get_result(); while($row = $result->fetch_assoc()) { $containers[] = $row; } $stmt->close(); } echo json_encode(['success' => true, 'data' => $containers]); break; case 'add_plant': if (empty($_POST['zone_id']) || empty($_POST['container_id']) || empty($_POST['seed_id']) || empty($_POST['plant_date'])) { echo json_encode(['success' => false, 'message' => 'Bitte alle Felder ausfüllen.']); exit; } $mysqli->begin_transaction(); $sql_insert = "INSERT INTO plants (user_id, zone_id, container_id, seed_id, plant_date, phase, status) VALUES (?, ?, ?, ?, ?, 'Keimend', 'Eingepflanzt')"; $stmt_insert = $mysqli->prepare($sql_insert); $stmt_insert->bind_param("iiiis", $user_id, $_POST['zone_id'], $_POST['container_id'], $_POST['seed_id'], $_POST['plant_date']); $stmt_insert->execute(); $new_plant_id = $stmt_insert->insert_id; $stmt_insert->close(); if (isset($_POST['reduce_seed_stock']) && $_POST['reduce_seed_stock'] == '1') { $sql_update = "UPDATE seeds SET stock_count = stock_count - 1 WHERE id = ? AND user_id = ? AND stock_count > 0"; $stmt_update = $mysqli->prepare($sql_update); $stmt_update->bind_param("ii", $_POST['seed_id'], $user_id); $stmt_update->execute(); $stmt_update->close(); } $sql_activity = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, 'Pflanzung', 'Pflanze wurde erstellt.', ?)"; $stmt_activity = $mysqli->prepare($sql_activity); $stmt_activity->bind_param("is", $new_plant_id, $_POST['plant_date']); $stmt_activity->execute(); $stmt_activity->close(); $mysqli->commit(); echo json_encode(['success' => true]); break; case 'edit_plant': if (empty($_POST['plant_id']) || empty($_POST['phase']) || empty($_POST['plant_date']) || empty($_POST['zone_id']) || empty($_POST['container_id'])) { echo json_encode(['success' => false, 'message' => 'Alle Felder sind Pflichtfelder.']); exit; } $mysqli->begin_transaction(); $old_phase_stmt = $mysqli->prepare("SELECT phase FROM plants WHERE id = ? AND user_id = ?"); $old_phase_stmt->bind_param("ii", $_POST['plant_id'], $user_id); $old_phase_stmt->execute(); $old_phase_result = $old_phase_stmt->get_result(); $old_phase = ($old_phase_result->num_rows > 0) ? $old_phase_result->fetch_assoc()['phase'] : null; $old_phase_stmt->close(); $sql = "UPDATE plants SET phase = ?, plant_date = ?, zone_id = ?, container_id = ? WHERE id = ? AND user_id = ?"; $stmt = $mysqli->prepare($sql); $stmt->bind_param("ssiiii", $_POST['phase'], $_POST['plant_date'], $_POST['zone_id'], $_POST['container_id'], $_POST['plant_id'], $user_id); $stmt->execute(); $stmt->close(); if ($old_phase !== null && $old_phase !== $_POST['phase']) { $note = "Phase geändert von '{$old_phase}' zu '{$_POST['phase']}'."; $sql_activity = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, 'Phasenwechsel', ?, NOW())"; $stmt_activity = $mysqli->prepare($sql_activity); $stmt_activity->bind_param("is", $_POST['plant_id'], $note); $stmt_activity->execute(); $stmt_activity->close(); } $mysqli->commit(); echo json_encode(['success' => true]); break; case 'delete_plant': if (empty($_POST['id']) || !is_numeric($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Ungültige Pflanzen-ID.']); exit; } $plant_id = $_POST['id']; $sql = "DELETE FROM plants WHERE id = ? AND user_id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $plant_id, $user_id); if ($stmt->execute()) { if ($stmt->affected_rows > 0) { echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'message' => 'Pflanze nicht gefunden oder keine Berechtigung.']); } } } break; case 'upload_plant_image': $plant_id = $_POST['plant_id'] ?? 0; if (empty($plant_id) || !isset($_FILES['plant_image'])) { echo json_encode(['success' => false, 'message' => 'Fehlende Daten.']); exit; } $sql_check = "SELECT id FROM plants WHERE id = ? AND user_id = ?"; $stmt_check = $mysqli->prepare($sql_check); $stmt_check->bind_param("ii", $plant_id, $user_id); $stmt_check->execute(); if ($stmt_check->get_result()->num_rows === 0) { echo json_encode(['success' => false, 'message' => 'Keine Berechtigung.']); exit; } $stmt_check->close(); $file = $_FILES['plant_image']; if ($file['error'] !== UPLOAD_ERR_OK) { echo json_encode(['success' => false, 'message' => 'Fehler beim Upload: ' . $file['error']]); exit; } $allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; if (!in_array($file['type'], $allowed_types)) { echo json_encode(['success' => false, 'message' => 'Ungültiger Dateityp.']); exit; } $upload_dir = 'uploads/user_' . $user_id . '/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true); } $file_extension = pathinfo($file['name'], PATHINFO_EXTENSION); $new_filename = uniqid('plant_' . $plant_id . '_', true) . '.' . $file_extension; $destination = $upload_dir . $new_filename; if (move_uploaded_file($file['tmp_name'], $destination)) { $sql_insert = "INSERT INTO plant_images (plant_id, user_id, file_path) VALUES (?, ?, ?)"; $stmt_insert = $mysqli->prepare($sql_insert); $stmt_insert->bind_param("iis", $plant_id, $user_id, $destination); $stmt_insert->execute(); $stmt_insert->close(); echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'message' => 'Datei konnte nicht verschoben werden.']); } break; case 'delete_plant_image': if (empty($_POST['id']) || !is_numeric($_POST['id'])) { echo json_encode(['success' => false, 'message' => 'Ungültige Bild-ID.']); exit; } $image_id = $_POST['id']; $file_path = ''; $sql_select = "SELECT pi.file_path FROM plant_images pi WHERE pi.id = ? AND pi.user_id = ?"; if ($stmt_select = $mysqli->prepare($sql_select)) { $stmt_select->bind_param("ii", $image_id, $user_id); $stmt_select->execute(); $result = $stmt_select->get_result(); if ($result->num_rows === 1) { $file_path = $result->fetch_assoc()['file_path']; } $stmt_select->close(); } if (empty($file_path)) { echo json_encode(['success' => false, 'message' => 'Bild nicht gefunden oder keine Berechtigung.']); exit; } $sql_delete = "DELETE FROM plant_images WHERE id = ? AND user_id = ?"; if ($stmt_delete = $mysqli->prepare($sql_delete)) { $stmt_delete->bind_param("ii", $image_id, $user_id); $stmt_delete->execute(); if ($stmt_delete->affected_rows > 0) { if (file_exists($file_path)) { unlink($file_path); } echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'message' => 'Fehler beim Löschen des Datenbankeintrags.']); } $stmt_delete->close(); } break; case 'harvest_plant': if (empty($_POST['plant_id']) || !is_numeric($_POST['plant_id'])) { echo json_encode(['success' => false, 'message' => 'Ungültige Pflanzen-ID.']); exit; } $plant_id = $_POST['plant_id']; $mysqli->begin_transaction(); $sql = "UPDATE plants SET status = 'Trocknend', phase = 'Ernte' WHERE id = ? AND user_id = ? AND status = 'Eingepflanzt'"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $plant_id, $user_id); $stmt->execute(); if ($stmt->affected_rows > 0) { $note = "Pflanze geerntet, Status auf 'Trocknend' gesetzt."; $sql_activity = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, 'Ernte', ?, NOW())"; $stmt_activity = $mysqli->prepare($sql_activity); $stmt_activity->bind_param("is", $plant_id, $note); $stmt_activity->execute(); $stmt_activity->close(); $mysqli->commit(); echo json_encode(['success' => true]); } else { $mysqli->rollback(); echo json_encode(['success' => false, 'message' => 'Aktion konnte nicht ausgeführt werden.']); } $stmt->close(); } break; case 'finish_drying': if (empty($_POST['plant_id']) || !is_numeric($_POST['plant_id'])) { echo json_encode(['success' => false, 'message' => 'Ungültige Pflanzen-ID.']); exit; } $plant_id = $_POST['plant_id']; $mysqli->begin_transaction(); $sql = "UPDATE plants SET status = 'Geerntet', phase = 'Getrocknet' WHERE id = ? AND user_id = ? AND status = 'Trocknend'"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $plant_id, $user_id); $stmt->execute(); if ($stmt->affected_rows > 0) { $note = "Trocknung abgeschlossen, Status auf 'Geerntet' gesetzt."; $sql_activity = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, 'Trocknung', ?, NOW())"; $stmt_activity = $mysqli->prepare($sql_activity); $stmt_activity->bind_param("is", $plant_id, $note); $stmt_activity->execute(); $stmt_activity->close(); $mysqli->commit(); echo json_encode(['success' => true]); } else { $mysqli->rollback(); echo json_encode(['success' => false, 'message' => 'Aktion konnte nicht ausgeführt werden.']); } $stmt->close(); } break; case 'add_activity': if (empty($_POST['plant_id']) || empty($_POST['activity_type']) || empty($_POST['activity_date'])) { echo json_encode(['success' => false, 'message' => 'Unvollständige Daten.']); exit; } $sql = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, ?, ?, ?)"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("isss", $_POST['plant_id'], $_POST['activity_type'], $_POST['note'], $_POST['activity_date']); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'add_measurement': if (empty($_POST['plant_id']) || !isset($_POST['height_cm']) || empty($_POST['measurement_date'])) { echo json_encode(['success' => false, 'message' => 'Unvollständige Daten.']); exit; } $sql = "INSERT INTO plant_height_measurements (plant_id, height_cm, measurement_date) VALUES (?, ?, ?)"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ids", $_POST['plant_id'], $_POST['height_cm'], $_POST['measurement_date']); $stmt->execute(); echo json_encode(['success' => true]); } break; case 'generate_api_key': $new_key = bin2hex(random_bytes(16)); $sql = "UPDATE users SET api_key = ? WHERE id = ?"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("si", $new_key, $user_id); if ($stmt->execute()) { echo json_encode(['success' => true, 'message' => 'Neuer API-Key wurde generiert.']); } } break; case 'change_username': if (empty(trim($_POST['username']))) { echo json_encode(['success' => false, 'message' => 'Benutzername darf nicht leer sein.']); exit; } $new_username = trim($_POST['username']); $sql_check = "SELECT id FROM users WHERE username = ? AND id != ?"; $stmt_check = $mysqli->prepare($sql_check); $stmt_check->bind_param("si", $new_username, $user_id); $stmt_check->execute(); if ($stmt_check->get_result()->num_rows > 0) { echo json_encode(['success' => false, 'message' => 'Dieser Benutzername ist bereits vergeben.']); exit; } $stmt_check->close(); $sql_update = "UPDATE users SET username = ? WHERE id = ?"; $stmt_update = $mysqli->prepare($sql_update); $stmt_update->bind_param("si", $new_username, $user_id); $stmt_update->execute(); $_SESSION['username'] = $new_username; echo json_encode(['success' => true, 'message' => 'Benutzername erfolgreich geändert.']); break; case 'change_password': if (empty($_POST['current_password']) || empty($_POST['new_password']) || empty($_POST['confirm_new_password'])) { echo json_encode(['success' => false, 'message' => 'Alle Felder sind erforderlich.']); exit; } if ($_POST['new_password'] !== $_POST['confirm_new_password']) { echo json_encode(['success' => false, 'message' => 'Die neuen Passwörter stimmen nicht überein.']); exit; } if (strlen($_POST['new_password']) < 6) { echo json_encode(['success' => false, 'message' => 'Das neue Passwort muss mindestens 6 Zeichen lang sein.']); exit; } $sql_pass = "SELECT password_hash FROM users WHERE id = ?"; $stmt_pass = $mysqli->prepare($sql_pass); $stmt_pass->bind_param("i", $user_id); $stmt_pass->execute(); $result_pass = $stmt_pass->get_result()->fetch_assoc(); $stmt_pass->close(); if (!password_verify($_POST['current_password'], $result_pass['password_hash'])) { echo json_encode(['success' => false, 'message' => 'Das aktuelle Passwort ist nicht korrekt.']); exit; } $new_password_hash = password_hash($_POST['new_password'], PASSWORD_DEFAULT); $sql_update_pass = "UPDATE users SET password_hash = ? WHERE id = ?"; $stmt_update_pass = $mysqli->prepare($sql_update_pass); $stmt_update_pass->bind_param("si", $new_password_hash, $user_id); $stmt_update_pass->execute(); echo json_encode(['success' => true, 'message' => 'Passwort erfolgreich geändert.']); break; case 'get_all_zones': $zones = []; $sql = "SELECT id, name FROM zones WHERE user_id = ? ORDER BY name ASC"; if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("i", $user_id); $stmt->execute(); $result = $stmt->get_result(); while($row = $result->fetch_assoc()) { $zones[] = $row; } $stmt->close(); } echo json_encode(['success' => true, 'data' => $zones]); break; case 'get_plants_by_zone': $zone_id = $_GET['zone_id'] ?? 'all'; $plants = []; $sql = "SELECT p.id, COALESCE(s.strain_name, '[Sorte gelöscht]') as strain_name, COALESCE(c.name, '[Gefäß gelöscht]') as container_name FROM plants p LEFT JOIN seeds s ON p.seed_id = s.id LEFT JOIN containers c ON p.container_id = c.id WHERE p.user_id = ? AND p.status = 'Eingepflanzt'"; if (is_numeric($zone_id)) { $sql .= " AND p.zone_id = ?"; $stmt = $mysqli->prepare($sql); $stmt->bind_param("ii", $user_id, $zone_id); } else { $stmt = $mysqli->prepare($sql); $stmt->bind_param("i", $user_id); } $stmt->execute(); $result = $stmt->get_result(); while($row = $result->fetch_assoc()) { $plants[] = $row; } $stmt->close(); echo json_encode(['success' => true, 'data' => $plants]); break; case 'add_global_activity': if (empty($_POST['activity_type']) || empty($_POST['activity_date']) || empty($_POST['plant_ids'])) { echo json_encode(['success' => false, 'message' => 'Unvollständige Daten.']); exit; } $plant_ids = $_POST['plant_ids']; $mysqli->begin_transaction(); $sql = "INSERT INTO plant_activities (plant_id, activity_type, note, activity_date) VALUES (?, ?, ?, ?)"; $stmt = $mysqli->prepare($sql); foreach($plant_ids as $plant_id) { $stmt->bind_param("isss", $plant_id, $_POST['activity_type'], $_POST['note'], $_POST['activity_date']); $stmt->execute(); } $stmt->close(); $mysqli->commit(); echo json_encode(['success' => true]); break; case 'get_sensor_data': if (empty($_GET['plant_id']) || !is_numeric($_GET['plant_id'])) { echo json_encode(['success' => false, 'message' => 'Ungültige Pflanzen-ID.']); exit; } $plant_id = $_GET['plant_id']; $sql_check = "SELECT id FROM plants WHERE id = ? AND user_id = ?"; $stmt_check = $mysqli->prepare($sql_check); $stmt_check->bind_param("ii", $plant_id, $user_id); $stmt_check->execute(); if ($stmt_check->get_result()->num_rows === 0) { echo json_encode(['success' => false, 'message' => 'Keine Berechtigung.']); exit; } $stmt_check->close(); $sql = "SELECT sensor_type, value, timestamp FROM sensor_data WHERE plant_id = ? ORDER BY timestamp ASC"; $stmt = $mysqli->prepare($sql); $stmt->bind_param("i", $plant_id); $stmt->execute(); $result = $stmt->get_result(); $raw_data = []; while ($row = $result->fetch_assoc()) { $raw_data[] = $row; } $stmt->close(); $data_by_timestamp = []; foreach ($raw_data as $row) { $timestamp = $row['timestamp']; if (!isset($data_by_timestamp[$timestamp])) { $data_by_timestamp[$timestamp] = ['temperatur' => null, 'feuchtigkeit' => null]; } if ($row['sensor_type'] == 'Temperatur') { $data_by_timestamp[$timestamp]['temperatur'] = (float)$row['value']; } elseif ($row['sensor_type'] == 'Feuchtigkeit') { $data_by_timestamp[$timestamp]['feuchtigkeit'] = (float)$row['value']; } } ksort($data_by_timestamp); $chart_data = ['labels' => [], 'temperature' => [], 'humidity' => []]; foreach ($data_by_timestamp as $timestamp => $values) { $chart_data['labels'][] = date('d.m H:i', strtotime($timestamp)); $chart_data['temperature'][] = $values['temperatur']; $chart_data['humidity'][] = $values['feuchtigkeit']; } echo json_encode(['success' => true, 'data' => $chart_data]); break; default: echo json_encode(['success' => false, 'message' => 'Unbekannte Aktion: ' . $action]); break; } } catch (mysqli_sql_exception $exception) { if ($mysqli->ping()) { $mysqli->rollback(); } error_log("[Cazubu Error] Datenbankfehler: " . $exception->getMessage()); echo json_encode(['success' => false, 'message' => 'Datenbankfehler: ' . $exception->getMessage()]); } $mysqli->close(); ?>