406 lines
16 KiB
PHP
406 lines
16 KiB
PHP
<?php
|
||
// product_add.php
|
||
|
||
require_once __DIR__ . '/lib/bootstrap.php';
|
||
|
||
/* =======================
|
||
0) Zugriffskontrolle – nur ADMIN
|
||
======================= */
|
||
if (empty($_SESSION['user_id']) || empty($_SESSION['user_roles']) || !in_array('ADMIN', $_SESSION['user_roles'], true)) {
|
||
http_response_code(403);
|
||
include 'header.php';
|
||
echo '<main class="auth"><section class="auth__grid"><div class="auth__card">';
|
||
echo '<h2 class="auth__title">Zugriff verweigert</h2>';
|
||
echo '<p>Du hast keine Berechtigung, Produkte hinzuzufügen.</p>';
|
||
echo '</div></section></main>';
|
||
include 'footer.php';
|
||
exit;
|
||
}
|
||
|
||
/* =======================
|
||
1) Kategorie aus GET
|
||
======================= */
|
||
$categoryID = 0;
|
||
if (isset($_GET['categoryID']) && ctype_digit($_GET['categoryID'])) {
|
||
$categoryID = (int)$_GET['categoryID'];
|
||
} elseif (isset($_POST['categoryID']) && ctype_digit($_POST['categoryID'])) {
|
||
$categoryID = (int)$_POST['categoryID'];
|
||
}
|
||
|
||
/* =======================
|
||
2) DB-Verbindung
|
||
======================= */
|
||
$conn = new mysqli("localhost", "FSST", "L9wUNZZ9Qkbt", "FSST", 3306);
|
||
if ($conn->connect_error) {
|
||
die("Datenbankfehler");
|
||
}
|
||
|
||
/* =======================
|
||
3) Kategorien laden
|
||
======================= */
|
||
$categories = [];
|
||
$result = $conn->query("
|
||
SELECT categoryID, name
|
||
FROM categories
|
||
ORDER BY name
|
||
");
|
||
while ($row = $result->fetch_assoc()) {
|
||
$categories[] = $row;
|
||
}
|
||
|
||
/* =======================
|
||
3b) Marken laden
|
||
======================= */
|
||
$brands = [];
|
||
$result = $conn->query("
|
||
SELECT brandID, name
|
||
FROM brands
|
||
ORDER BY name
|
||
");
|
||
while ($row = $result->fetch_assoc()) {
|
||
$brands[] = $row;
|
||
}
|
||
|
||
/* =======================
|
||
4) Attribute zur Kategorie
|
||
======================= */
|
||
$attributes = [];
|
||
if ($categoryID > 0) {
|
||
$stmt = $conn->prepare("
|
||
SELECT a.attributeID, a.name, a.unit, a.dataType
|
||
FROM categoryAttributes ca
|
||
JOIN attributes a ON a.attributeID = ca.attributeID
|
||
WHERE ca.categoryID = ?
|
||
ORDER BY a.name
|
||
");
|
||
$stmt->bind_param("i", $categoryID);
|
||
$stmt->execute();
|
||
$res = $stmt->get_result();
|
||
while ($row = $res->fetch_assoc()) {
|
||
$attributes[] = $row;
|
||
}
|
||
}
|
||
|
||
/* =======================
|
||
5) Produkt speichern
|
||
======================= */
|
||
$saveError = null;
|
||
$debugMode = isset($_GET['debug']) && $_GET['debug'] === '1';
|
||
$debugDetails = [];
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['saveProduct'])) {
|
||
|
||
$model = trim($_POST['model']);
|
||
$description = $_POST['description'] ?? null;
|
||
$categoryID = (int)$_POST['categoryID'];
|
||
$brandID = (int)($_POST['brandID'] ?? 0);
|
||
|
||
$imageUrl = trim((string)($_POST['imageUrl'] ?? ''));
|
||
$imageFile = (isset($_FILES['productImage']) && is_array($_FILES['productImage'])) ? $_FILES['productImage'] : null;
|
||
$hasUpload = $imageFile && isset($imageFile['error']) && (int)$imageFile['error'] !== UPLOAD_ERR_NO_FILE;
|
||
$uploadMime = null;
|
||
|
||
if ($debugMode) {
|
||
$debugDetails['post_categoryID'] = $_POST['categoryID'] ?? null;
|
||
$debugDetails['post_brandID'] = $_POST['brandID'] ?? null;
|
||
$debugDetails['post_model'] = $model;
|
||
$debugDetails['file_present'] = $imageFile !== null ? 'yes' : 'no';
|
||
$debugDetails['file_error'] = $imageFile['error'] ?? null;
|
||
$debugDetails['file_name'] = $imageFile['name'] ?? null;
|
||
$debugDetails['file_size'] = $imageFile['size'] ?? null;
|
||
$debugDetails['file_tmp'] = isset($imageFile['tmp_name']) ? (string)$imageFile['tmp_name'] : null;
|
||
$debugDetails['upload_max_filesize'] = ini_get('upload_max_filesize');
|
||
$debugDetails['post_max_size'] = ini_get('post_max_size');
|
||
}
|
||
|
||
if ($categoryID <= 0) {
|
||
$saveError = 'Bitte eine Kategorie auswählen.';
|
||
} elseif ($brandID <= 0) {
|
||
$saveError = 'Bitte eine Marke auswählen.';
|
||
} elseif ($model === '') {
|
||
$saveError = 'Bitte ein Modell angeben.';
|
||
} elseif ($imageUrl !== '' && !filter_var($imageUrl, FILTER_VALIDATE_URL)) {
|
||
$saveError = 'Bitte eine gueltige Bild-URL eingeben.';
|
||
} elseif ($hasUpload) {
|
||
$fileError = (int)$imageFile['error'];
|
||
if ($fileError !== UPLOAD_ERR_OK) {
|
||
$saveError = 'Bild-Upload fehlgeschlagen (Code ' . $fileError . ').';
|
||
} else {
|
||
$tmp = isset($imageFile['tmp_name']) ? (string)$imageFile['tmp_name'] : '';
|
||
if ($tmp === '' || !is_uploaded_file($tmp)) {
|
||
$saveError = 'Upload-Datei ungueltig.';
|
||
} else {
|
||
$allowedMimeToExt = [
|
||
'image/jpeg' => 'jpg',
|
||
'image/png' => 'png',
|
||
];
|
||
|
||
$mime = null;
|
||
$imageInfo = @getimagesize($tmp);
|
||
$imageType = (is_array($imageInfo) && isset($imageInfo[2])) ? (int)$imageInfo[2] : null;
|
||
|
||
if ($imageType === IMAGETYPE_PNG) {
|
||
$mime = 'image/png';
|
||
} elseif ($imageType === IMAGETYPE_JPEG) {
|
||
$mime = 'image/jpeg';
|
||
}
|
||
|
||
if (!$mime) {
|
||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||
$mime = $finfo->file($tmp);
|
||
}
|
||
|
||
$fileExt = strtolower(pathinfo((string)($imageFile['name'] ?? ''), PATHINFO_EXTENSION));
|
||
if ($debugMode) {
|
||
$debugDetails['getimagesize_mime'] = $imageInfo['mime'] ?? null;
|
||
$debugDetails['getimagesize_type'] = $imageType;
|
||
$debugDetails['finfo_mime'] = $mime;
|
||
$debugDetails['file_ext'] = $fileExt;
|
||
}
|
||
|
||
if (!$mime || !isset($allowedMimeToExt[$mime])) {
|
||
if (in_array($fileExt, ['jpg', 'jpeg', 'png'], true)) {
|
||
$uploadMime = ($fileExt === 'png') ? 'image/png' : 'image/jpeg';
|
||
} else {
|
||
$saveError = 'Nur JPG oder PNG sind erlaubt. Erkannter Typ: ' . ($mime ?: 'unbekannt');
|
||
}
|
||
} else {
|
||
$uploadMime = $mime;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($saveError === null) {
|
||
// --- Produkt anlegen ---
|
||
$stmt = $conn->prepare("
|
||
INSERT INTO products (categoryID, brandID, model, description)
|
||
VALUES (?, ?, ?, ?)
|
||
");
|
||
if (!$stmt) {
|
||
$saveError = 'Datenbankfehler beim Anlegen des Produkts.';
|
||
} else {
|
||
$stmt->bind_param("iiss", $categoryID, $brandID, $model, $description);
|
||
$ok = $stmt->execute();
|
||
|
||
if (!$ok) {
|
||
error_log('Product insert failed: ' . $stmt->error);
|
||
$saveError = 'Produkt konnte nicht gespeichert werden (DB-Fehler).';
|
||
if ($debugMode) {
|
||
$debugDetails['db_error'] = $stmt->error;
|
||
}
|
||
} else {
|
||
$productID = $stmt->insert_id;
|
||
|
||
$publicImagePath = null;
|
||
|
||
if ($hasUpload) {
|
||
$relativeTargetDir = 'assets/images/products';
|
||
$dirTargetDir = rtrim(__DIR__, "\\/") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativeTargetDir);
|
||
$documentRoot = isset($_SERVER['DOCUMENT_ROOT']) ? (string)$_SERVER['DOCUMENT_ROOT'] : '';
|
||
$docRootTrim = rtrim($documentRoot, "\\/");
|
||
$docTargetDir = ($docRootTrim !== '')
|
||
? $docRootTrim . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativeTargetDir)
|
||
: '';
|
||
|
||
$targetDir = $dirTargetDir;
|
||
if ($docTargetDir !== '' && !is_dir($dirTargetDir) && is_dir($docTargetDir)) {
|
||
$targetDir = $docTargetDir;
|
||
}
|
||
|
||
if (!is_dir($targetDir) && !@mkdir($targetDir, 0755, true)) {
|
||
$saveError = 'Zielordner fuer Upload nicht verfuegbar.';
|
||
} elseif (!is_writable($targetDir)) {
|
||
$saveError = 'Zielordner ist nicht beschreibbar.';
|
||
} else {
|
||
$tmp = (string)$imageFile['tmp_name'];
|
||
$mime = $uploadMime;
|
||
if (!$mime) {
|
||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||
$mime = $finfo->file($tmp);
|
||
}
|
||
|
||
$filename = $productID . '.png';
|
||
$targetPath = rtrim($targetDir, "\\/") . DIRECTORY_SEPARATOR . $filename;
|
||
|
||
$savedOk = false;
|
||
if ($mime === 'image/png') {
|
||
$savedOk = move_uploaded_file($tmp, $targetPath);
|
||
} elseif ($mime === 'image/jpeg') {
|
||
$sourceImage = @imagecreatefromjpeg($tmp);
|
||
if ($sourceImage !== false) {
|
||
$savedOk = imagepng($sourceImage, $targetPath);
|
||
imagedestroy($sourceImage);
|
||
}
|
||
}
|
||
|
||
if ($savedOk) {
|
||
$publicImagePath = $relativeTargetDir . '/' . $filename;
|
||
} else {
|
||
$saveError = 'Bild konnte nicht gespeichert werden.';
|
||
}
|
||
}
|
||
} elseif ($imageUrl !== '') {
|
||
$publicImagePath = $imageUrl;
|
||
}
|
||
|
||
if ($saveError === null && $publicImagePath !== null) {
|
||
$stmtImg = $conn->prepare("UPDATE products SET imagePath = ? WHERE productID = ?");
|
||
if ($stmtImg) {
|
||
$stmtImg->bind_param("si", $publicImagePath, $productID);
|
||
$stmtImg->execute();
|
||
}
|
||
}
|
||
|
||
// --- Attribute speichern ---
|
||
if (!empty($_POST['attributes'])) {
|
||
|
||
$stmtAttr = $conn->prepare("
|
||
INSERT INTO productAttributes
|
||
(productID, attributeID, valueString, valueNumber, valueBool)
|
||
VALUES (?, ?, ?, ?, ?)
|
||
");
|
||
|
||
foreach ($_POST['attributes'] as $attributeID => $value) {
|
||
|
||
if ($value === '' || $value === null) {
|
||
continue;
|
||
}
|
||
|
||
$valueString = null;
|
||
$valueNumber = null;
|
||
$valueBool = null;
|
||
|
||
if (is_numeric($value)) {
|
||
$valueNumber = $value;
|
||
} elseif ($value === '0' || $value === '1') {
|
||
$valueBool = (int)$value;
|
||
} else {
|
||
$valueString = trim($value);
|
||
}
|
||
|
||
$stmtAttr->bind_param(
|
||
"iisdi",
|
||
$productID,
|
||
$attributeID,
|
||
$valueString,
|
||
$valueNumber,
|
||
$valueBool
|
||
);
|
||
$stmtAttr->execute();
|
||
}
|
||
}
|
||
|
||
if ($saveError === null) {
|
||
header("Location: productAdder.php?categoryID=" . $categoryID);
|
||
exit;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
include 'header.php';
|
||
?>
|
||
|
||
|
||
<main class="auth">
|
||
<section class="auth__grid">
|
||
|
||
<!-- Kategorie waehlen -->
|
||
<div class="auth__card">
|
||
<header class="auth__header">
|
||
<h2 class="auth__title">Kategorie wählen</h2>
|
||
</header>
|
||
<form method="get" class="auth__form">
|
||
<div class="auth__select__wrap">
|
||
<label class="auth__select__label" for="categoryID">Kategorie</label>
|
||
<select id="categoryID" name="categoryID" class="auth__select" onchange="this.form.submit()" required>
|
||
<option value="">Kategorie wählen</option>
|
||
<?php foreach ($categories as $cat): ?>
|
||
<option value="<?= $cat['categoryID'] ?>"
|
||
<?= $cat['categoryID'] === $categoryID ? 'selected' : '' ?>>
|
||
<?= htmlspecialchars($cat['name']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Produkt anlegen -->
|
||
<?php if ($categoryID > 0): ?>
|
||
<div class="auth__card">
|
||
<header class="auth__header">
|
||
<h2 class="auth__title">Produkt hinzufügen</h2>
|
||
</header>
|
||
|
||
<form method="post" class="auth__form" enctype="multipart/form-data">
|
||
<input type="hidden" name="categoryID" value="<?= $categoryID ?>">
|
||
|
||
<?php if ($saveError): ?>
|
||
<p class="auth__error"><?= htmlspecialchars($saveError) ?></p>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($debugMode && !empty($debugDetails)): ?>
|
||
<pre class="auth__error"><?= htmlspecialchars(print_r($debugDetails, true)) ?></pre>
|
||
<?php endif; ?>
|
||
|
||
<label for="brandID">Marke</label>
|
||
<select id="brandID" name="brandID" class="auth__select" required>
|
||
<option value="">Marke wählen</option>
|
||
<?php foreach ($brands as $brand): ?>
|
||
<option value="<?= $brand['brandID'] ?>">
|
||
<?= htmlspecialchars($brand['name']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
|
||
<label for="model">Modell</label>
|
||
<input id="model" type="text" name="model" class="auth__input" required>
|
||
|
||
<label for="description">Beschreibung</label>
|
||
<textarea id="description" name="description" class="auth__input"></textarea>
|
||
|
||
<label for="productImage">Produktbild hochladen (PNG oder JPG)</label>
|
||
<div class="auth__field">
|
||
<input id="productImage" type="file" name="productImage" accept="image/*">
|
||
<p class="auth__tip">Erlaubt: JPG/PNG. max. 20MB.</p>
|
||
</div>
|
||
|
||
<label for="imageUrl">oder Bild-URL</label>
|
||
<input id="imageUrl" type="url" name="imageUrl" class="auth__input" placeholder="https://...">
|
||
|
||
<h3 class="auth__title">Attribute</h3>
|
||
|
||
<?php foreach ($attributes as $attr): ?>
|
||
<label>
|
||
<?= htmlspecialchars($attr['name']) ?>
|
||
<?php if ($attr['unit']): ?>
|
||
(<?= htmlspecialchars($attr['unit']) ?>)
|
||
<?php endif; ?>
|
||
</label>
|
||
|
||
<input
|
||
type="<?= $attr['dataType'] === 'number' ? 'number' : 'text' ?>"
|
||
name="attributes[<?= $attr['attributeID'] ?>]"
|
||
class="auth__input"
|
||
>
|
||
<?php endforeach; ?>
|
||
|
||
<div class="auth__actions">
|
||
<button type="submit" name="saveProduct" class="auth__submit">
|
||
Produkt speichern
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
</section>
|
||
</main>
|
||
|
||
<?php
|
||
$conn->close();
|
||
include 'footer.php';
|
||
?>
|