feat: refactor into php for mrbs page
This commit is contained in:
25
php/.htaccess
Normal file
25
php/.htaccess
Normal file
@@ -0,0 +1,25 @@
|
||||
# Prevent directory browsing
|
||||
Options -Indexes
|
||||
|
||||
# Enable rewrite engine (optional, for clean URLs)
|
||||
RewriteEngine On
|
||||
|
||||
# Redirect /semesterapparat to semesterapparat.php
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^semesterapparat$ semesterapparat.php [L]
|
||||
|
||||
# Redirect /elsa to elsa.php
|
||||
RewriteRule ^elsa$ elsa.php [L]
|
||||
|
||||
# Protect config files
|
||||
<FilesMatch "^(config|functions)\.php$">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Set default charset
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
# Error pages (customize as needed)
|
||||
ErrorDocument 404 /index.php
|
||||
155
php/README.md
Normal file
155
php/README.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# PHP Deployment Guide for SemapForm
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 7.4 or higher (PHP 8+ recommended)
|
||||
- PHP extensions:
|
||||
- `dom` (for XML generation)
|
||||
- `mbstring` (for string handling)
|
||||
- `openssl` (for SMTP if using SSL/TLS)
|
||||
- Web server (Apache, Nginx, or any PHP-capable server)
|
||||
- Optional: PHPMailer library for advanced SMTP support
|
||||
|
||||
## Installation Steps
|
||||
|
||||
1. **Upload files to your PHP server:**
|
||||
```
|
||||
php/
|
||||
├── index.php
|
||||
├── semesterapparat.php
|
||||
├── submit_semesterapparat.php
|
||||
├── config.php
|
||||
├── functions.php
|
||||
├── .htaccess (if using Apache)
|
||||
└── static/
|
||||
└── styles.css
|
||||
```
|
||||
|
||||
2. **Configure email settings:**
|
||||
|
||||
Edit `config.php` or set environment variables:
|
||||
- `MAIL_ENABLED`: Set to `true` to enable email sending
|
||||
- `SMTP_HOST`: Your SMTP server (e.g., smtp.ph-freiburg.de)
|
||||
- `SMTP_PORT`: SMTP port (465 for SSL, 587 for TLS, 25 for plain)
|
||||
- `SMTP_USERNAME`: Your SMTP username
|
||||
- `SMTP_PASSWORD`: Your SMTP password
|
||||
- `MAIL_FROM`: Sender email address
|
||||
- `MAIL_TO`: Recipient email address
|
||||
|
||||
3. **Set permissions:**
|
||||
```bash
|
||||
chmod 755 *.php
|
||||
chmod 644 config.php
|
||||
chmod 644 static/styles.css
|
||||
```
|
||||
|
||||
4. **Test the installation:**
|
||||
- Navigate to your server URL (e.g., `https://yourserver.com/php/`)
|
||||
- Try submitting a test form
|
||||
- Check email delivery or server logs
|
||||
|
||||
## Email Configuration Options
|
||||
|
||||
### Option 1: PHP's built-in mail() function
|
||||
- Simplest setup
|
||||
- Requires server to have mail transfer agent (MTA) configured
|
||||
- No additional configuration needed in PHP
|
||||
|
||||
### Option 2: SMTP with PHP's native functions
|
||||
- Configure SMTP settings in `config.php`
|
||||
- Works with basic authentication
|
||||
- Current implementation in `functions.php`
|
||||
|
||||
### Option 3: PHPMailer (Recommended for production)
|
||||
- Install PHPMailer via Composer:
|
||||
```bash
|
||||
composer require phpmailer/phpmailer
|
||||
```
|
||||
- Better error handling and SMTP support
|
||||
- Already integrated in `functions.php` (will auto-detect if available)
|
||||
|
||||
## Server-Specific Notes
|
||||
|
||||
### Apache
|
||||
- The `.htaccess` file is included for URL rewriting and security
|
||||
- Ensure `mod_rewrite` is enabled
|
||||
|
||||
### Nginx
|
||||
- Add this to your nginx.conf:
|
||||
```nginx
|
||||
location /php {
|
||||
index index.php;
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass unix:/var/run/php/php-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shared Hosting
|
||||
- Most shared hosts have PHP and mail() pre-configured
|
||||
- Upload files via FTP/SFTP
|
||||
- Set environment variables through hosting control panel
|
||||
- Test mail() function first before adding SMTP
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Emails not sending
|
||||
1. Check `MAIL_ENABLED` is set to `true`
|
||||
2. Verify SMTP credentials are correct
|
||||
3. Check server error logs: `tail -f /var/log/apache2/error.log`
|
||||
4. Test with `MAIL_ENABLED=false` to see XML output in logs
|
||||
|
||||
### Form validation errors
|
||||
- Ensure all required fields have values
|
||||
- Check email format validation
|
||||
- Verify POST data is being received
|
||||
|
||||
### Permission errors
|
||||
- Ensure PHP has read access to all files
|
||||
- Check web server user/group permissions
|
||||
|
||||
## Security Recommendations
|
||||
|
||||
1. **Move config.php outside web root** if possible
|
||||
2. **Use environment variables** for sensitive data
|
||||
3. **Enable HTTPS** for form submissions
|
||||
4. **Sanitize all inputs** (already implemented in `functions.php`)
|
||||
5. **Set production error reporting** in `config.php`:
|
||||
```php
|
||||
error_reporting(0);
|
||||
ini_set('display_errors', 0);
|
||||
```
|
||||
6. **Regular updates**: Keep PHP and server software updated
|
||||
|
||||
## Migrating from Docker/Python
|
||||
|
||||
The PHP version maintains feature parity with the Python/FastAPI version:
|
||||
- ✅ Same form fields and validation
|
||||
- ✅ XML generation with identical structure
|
||||
- ✅ Email sending with SMTP support
|
||||
- ✅ Same CSS and frontend behavior
|
||||
- ✅ Theme toggle functionality
|
||||
- ✅ Multi-book/media support
|
||||
- ✅ Optional fields (title, signature, Dauerapparat)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
You can set these as server environment variables instead of editing `config.php`:
|
||||
|
||||
```bash
|
||||
export MAIL_ENABLED=true
|
||||
export SMTP_HOST=smtp.ph-freiburg.de
|
||||
export SMTP_PORT=465
|
||||
export MAIL_USERNAME=your_username
|
||||
export MAIL_PASSWORD=your_password
|
||||
export MAIL_FROM=alexander.kirchner@ph-freiburg.de
|
||||
export MAIL_TO=semesterapparate@ph-freiburg.de
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues specific to your hosting environment, consult your hosting provider's PHP documentation.
|
||||
28
php/config.php
Normal file
28
php/config.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* Configuration file for SemapForm PHP Application
|
||||
*
|
||||
* Copy this file and adjust values for your environment.
|
||||
* For production, consider loading from environment variables or a .env file
|
||||
*/
|
||||
|
||||
// Error reporting (set to 0 in production)
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Email configuration
|
||||
define('MAIL_ENABLED', getenv('MAIL_ENABLED') !== false ? filter_var(getenv('MAIL_ENABLED'), FILTER_VALIDATE_BOOLEAN) : true);
|
||||
define('SMTP_HOST', getenv('SMTP_HOST') ?: 'smtp.ph-freiburg.de');
|
||||
define('SMTP_PORT', getenv('SMTP_PORT') ?: 465);
|
||||
define('SMTP_ENCRYPTION', 'ssl'); // 'ssl' or 'tls' or '' for none
|
||||
define('SMTP_USERNAME', getenv('MAIL_USERNAME') ?: '');
|
||||
define('SMTP_PASSWORD', getenv('MAIL_PASSWORD') ?: '');
|
||||
define('MAIL_FROM', getenv('MAIL_FROM') ?: 'alexander.kirchner@ph-freiburg.de');
|
||||
define('MAIL_TO', getenv('MAIL_TO') ?: 'semesterapparate@ph-freiburg.de');
|
||||
|
||||
// Application settings
|
||||
define('BASE_PATH', __DIR__);
|
||||
define('STATIC_PATH', '/static');
|
||||
|
||||
// Email regex pattern
|
||||
define('EMAIL_REGEX', '/^[^@\s]+@[^@\s]+\.[^@\s]+$/');
|
||||
321
php/elsa.php
Normal file
321
php/elsa.php
Normal file
@@ -0,0 +1,321 @@
|
||||
<?php require_once 'config.php'; ?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ELSA - Elektronischer Semesterapparat</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="<?php echo STATIC_PATH; ?>/styles.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<div class="header-left">
|
||||
<img class="logo" src="https://www.ph-freiburg.de/_assets/cc3dd7db45300ecc1f3aeed85bda5532/Images/logo-big-blue.svg" alt="PH Freiburg Logo" />
|
||||
<div class="brand">
|
||||
<div class="brand-title">Bibliothek der Pädagogischen Hochschule Freiburg</div>
|
||||
<div class="brand-sub">Hochschulbibliothek · ELSA</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="theme-toggle" class="theme-toggle" aria-label="Switch to dark mode" title="Switch to dark mode">
|
||||
<span class="mdi mdi-theme-light-dark" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<section class="card">
|
||||
<h1>ELSA - Elektronischer Semesterapparat</h1>
|
||||
|
||||
<div class="legal-notice">
|
||||
<h3><span class="mdi mdi-information"></span> Rechtlicher Hinweis</h3>
|
||||
<p>
|
||||
Das Urheberrecht gestattet gemäß § 60a UrhG zur Veranschaulichung des Unterrichts die Bereitstellung elektronischer Kopien bis max. 15% von veröffentlichten Werken, von einzelnen Aufsätzen aus Fachzeitschriften und von Werken geringen Umfangs (max. 25 S. Gesamtumfang) für einen genau abgegrenzten Benutzerkreis wie den Teilnehmenden einer Lehrveranstaltung, die sich auf ILIAS angemeldet haben.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post" action="submit_elsa.php" class="request-form">
|
||||
<h2>Allgemeine Informationen</h2>
|
||||
<div class="grid-form">
|
||||
<div class="form-field">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" name="name" id="name" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="lastname">Nachname</label>
|
||||
<input type="text" name="lastname" id="lastname" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="title">Titel (optional)</label>
|
||||
<input type="text" name="title" id="title">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="mail">Email</label>
|
||||
<input type="email" name="mail" id="mail" required>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="subject">Fach</label>
|
||||
<select name="subject" id="subject" required>
|
||||
<option value="">-- Auswählen --</option>
|
||||
<option>Biologie</option>
|
||||
<option>Chemie</option>
|
||||
<option>Deutsch</option>
|
||||
<option>Englisch</option>
|
||||
<option>Erziehungswirtschaft</option>
|
||||
<option>Französisch</option>
|
||||
<option>Geographie</option>
|
||||
<option>Geschichte</option>
|
||||
<option>Gesundheitspädagogik</option>
|
||||
<option>Haushalt / Textil</option>
|
||||
<option>Kunst</option>
|
||||
<option>Mathematik / Informatik</option>
|
||||
<option>Medien in der Bildung</option>
|
||||
<option>Musik</option>
|
||||
<option>Philosophie</option>
|
||||
<option>Physik</option>
|
||||
<option>Politikwissenschaft</option>
|
||||
<option>Prorektorat Lehre und Studium</option>
|
||||
<option>Psychologie</option>
|
||||
<option>Soziologie</option>
|
||||
<option>Sport</option>
|
||||
<option>Technik</option>
|
||||
<option>Theologie</option>
|
||||
<option>Wirtschaftslehre</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="classname">Veranstaltungsname</label>
|
||||
<input type="text" name="classname" id="classname" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="usage_date_from">Nutzungszeitraum von</label>
|
||||
<input type="date" name="usage_date_from" id="usage_date_from" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="usage_date_to">Nutzungszeitraum bis</label>
|
||||
<input type="date" name="usage_date_to" id="usage_date_to" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="availability_date">Bereitstellungsdatum</label>
|
||||
<input type="date" name="availability_date" id="availability_date" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Medien</h2>
|
||||
<div class="media-controls">
|
||||
<button type="button" id="btn-monografie" class="btn btn-secondary" onclick="addMediaType('monografie')" title="Monografie Sektion hinzufügen">
|
||||
<span class="mdi mdi-book"></span> + Monografie
|
||||
</button>
|
||||
<button type="button" id="btn-zeitschriftenartikel" class="btn btn-secondary" onclick="addMediaType('zeitschriftenartikel')" title="Zeitschriftenartikel Sektion hinzufügen">
|
||||
<span class="mdi mdi-newspaper"></span> + Zeitschriftenartikel
|
||||
</button>
|
||||
<button type="button" id="btn-herausgeberwerk" class="btn btn-secondary" onclick="addMediaType('herausgeberwerk')" title="Herausgeberwerk Sektion hinzufügen">
|
||||
<span class="mdi mdi-book-multiple"></span> + Herausgeberwerk
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="media-sections"></div>
|
||||
|
||||
<div class="form-field" style="margin-top: 20px;">
|
||||
<label for="message">Nachricht (optional)</label>
|
||||
<textarea name="message" id="message" rows="4" placeholder="Zusätzliche Anmerkungen oder Hinweise..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-primary">Absenden</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
let mediaCounter = {
|
||||
monografie: 0,
|
||||
zeitschriftenartikel: 0,
|
||||
herausgeberwerk: 0
|
||||
};
|
||||
|
||||
let sectionCounter = 0;
|
||||
|
||||
// Theme toggle functionality
|
||||
(function() {
|
||||
const STORAGE_KEY = 'theme';
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
|
||||
function setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem(STORAGE_KEY, theme);
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
const label = theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
|
||||
btn.setAttribute('aria-label', label);
|
||||
btn.title = label;
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(saved || (prefersDark ? 'dark' : 'light'));
|
||||
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', () => {
|
||||
const current = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
||||
setTheme(current === 'dark' ? 'light' : 'dark');
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
function addMediaType(type) {
|
||||
const btn = document.getElementById('btn-' + type);
|
||||
if (btn && btn.disabled) { return; }
|
||||
const container = document.getElementById('media-sections');
|
||||
const sectionId = 'section-' + sectionCounter++;
|
||||
|
||||
const section = document.createElement('div');
|
||||
section.className = 'media-section';
|
||||
section.id = sectionId;
|
||||
section.setAttribute('data-type', type);
|
||||
|
||||
let title = '';
|
||||
let tableHtml = '';
|
||||
|
||||
if (type === 'monografie') {
|
||||
title = 'Monografie';
|
||||
tableHtml = '<table class="data-table media-table" id="table-' + sectionId + '">' +
|
||||
'<tr>' +
|
||||
'<th>Autor<br>(Nachname, Vorname)</th>' +
|
||||
'<th>Jahr</th>' +
|
||||
'<th>Auflage</th>' +
|
||||
'<th>Titel</th>' +
|
||||
'<th>Signatur</th>' +
|
||||
'<th>Seiten von</th>' +
|
||||
'<th>Seiten bis</th>' +
|
||||
'<th></th>' +
|
||||
'</tr>' +
|
||||
'</table>';
|
||||
} else if (type === 'zeitschriftenartikel') {
|
||||
title = 'Zeitschriftenartikel';
|
||||
tableHtml = '<table class="data-table media-table" id="table-' + sectionId + '">' +
|
||||
'<tr>' +
|
||||
'<th>Autor<br>(Nachname, Vorname)</th>' +
|
||||
'<th>Jahr</th>' +
|
||||
'<th>Band</th>' +
|
||||
'<th>Titel des Artikels</th>' +
|
||||
'<th>Titel der Zeitschrift</th>' +
|
||||
'<th>Signatur</th>' +
|
||||
'<th>Seiten von</th>' +
|
||||
'<th>Seiten bis</th>' +
|
||||
'<th></th>' +
|
||||
'</tr>' +
|
||||
'</table>';
|
||||
} else if (type === 'herausgeberwerk') {
|
||||
title = 'Herausgeberwerk';
|
||||
tableHtml = '<table class="data-table media-table" id="table-' + sectionId + '">' +
|
||||
'<tr>' +
|
||||
'<th>Herausgeber<br>(Nachname, Vorname)</th>' +
|
||||
'<th>Titel des Werks</th>' +
|
||||
'<th>Jahr</th>' +
|
||||
'<th>Auflage</th>' +
|
||||
'<th>Autor des Artikels<br>(Nachname, Vorname)</th>' +
|
||||
'<th>Titel des Artikels</th>' +
|
||||
'<th>Signatur</th>' +
|
||||
'<th>Seiten von</th>' +
|
||||
'<th>Seiten bis</th>' +
|
||||
'<th></th>' +
|
||||
'</tr>' +
|
||||
'</table>';
|
||||
}
|
||||
|
||||
section.innerHTML = '<div class="media-section-header">' +
|
||||
'<h3><span class="mdi ' + getIconForType(type) + '"></span> ' + title + '</h3>' +
|
||||
'<button type="button" class="btn-icon" onclick="removeMediaSection(\'' + sectionId + '\')" title="Sektion entfernen">' +
|
||||
'<span class="mdi mdi-close"></span>' +
|
||||
'</button>' +
|
||||
'</div>' +
|
||||
tableHtml +
|
||||
'<button type="button" class="btn btn-secondary btn-sm" onclick="addMediaRow(\'' + sectionId + '\', \'' + type + '\')">' +
|
||||
'+ Eintrag hinzufügen' +
|
||||
'</button>';
|
||||
|
||||
container.appendChild(section);
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.title = 'Sektion bereits hinzugefügt';
|
||||
}
|
||||
|
||||
addMediaRow(sectionId, type);
|
||||
}
|
||||
|
||||
function getIconForType(type) {
|
||||
const icons = {
|
||||
'monografie': 'mdi-book',
|
||||
'zeitschriftenartikel': 'mdi-newspaper',
|
||||
'herausgeberwerk': 'mdi-book-multiple'
|
||||
};
|
||||
return icons[type] || 'mdi-file';
|
||||
}
|
||||
|
||||
function addMediaRow(sectionId, type) {
|
||||
const table = document.getElementById('table-' + sectionId);
|
||||
const row = table.insertRow(-1);
|
||||
const rowId = sectionId + '-row-' + mediaCounter[type]++;
|
||||
row.id = rowId;
|
||||
|
||||
if (type === 'monografie') {
|
||||
row.innerHTML = '<td><input type="text" name="monografie_author[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="monografie_year[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="monografie_edition[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="monografie_title[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="monografie_signature[]" data-section="' + sectionId + '" placeholder="Optional"></td>' +
|
||||
'<td><input type="number" name="monografie_pages_from[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><input type="number" name="monografie_pages_to[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><button type="button" class="btn-icon" onclick="removeRow(\'' + rowId + '\')" title="Zeile entfernen"><span class="mdi mdi-delete"></span></button></td>';
|
||||
} else if (type === 'zeitschriftenartikel') {
|
||||
row.innerHTML = '<td><input type="text" name="zeitschrift_author[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_year[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_volume[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_article_title[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_journal_title[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="zeitschrift_signature[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="number" name="zeitschrift_pages_from[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><input type="number" name="zeitschrift_pages_to[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><button type="button" class="btn-icon" onclick="removeRow(\'' + rowId + '\')" title="Zeile entfernen"><span class="mdi mdi-delete"></span></button></td>';
|
||||
} else if (type === 'herausgeberwerk') {
|
||||
row.innerHTML = '<td><input type="text" name="herausgeber_publisher[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_work_title[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_year[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_edition[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_article_author[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_article_title[]" data-section="' + sectionId + '" required></td>' +
|
||||
'<td><input type="text" name="herausgeber_signature[]" data-section="' + sectionId + '" placeholder="Optional"></td>' +
|
||||
'<td><input type="number" name="herausgeber_pages_from[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><input type="number" name="herausgeber_pages_to[]" data-section="' + sectionId + '" required min="1"></td>' +
|
||||
'<td><button type="button" class="btn-icon" onclick="removeRow(\'' + rowId + '\')" title="Zeile entfernen"><span class="mdi mdi-delete"></span></button></td>';
|
||||
}
|
||||
}
|
||||
|
||||
function removeRow(rowId) {
|
||||
const row = document.getElementById(rowId);
|
||||
if (row) {
|
||||
row.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function removeMediaSection(sectionId) {
|
||||
const section = document.getElementById(sectionId);
|
||||
if (section) {
|
||||
if (confirm('Möchten Sie diese Sektion wirklich entfernen?')) {
|
||||
const type = section.getAttribute('data-type');
|
||||
section.remove();
|
||||
const btn = document.getElementById('btn-' + type);
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
btn.title = 'Sektion hinzufügen';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
218
php/functions.php
Normal file
218
php/functions.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
/**
|
||||
* Validate email address
|
||||
*/
|
||||
function validateEmail($email) {
|
||||
return preg_match(EMAIL_REGEX, $email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize input string
|
||||
*/
|
||||
function sanitizeInput($input) {
|
||||
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate XML from form data
|
||||
*/
|
||||
function generateXML($data) {
|
||||
$xml = new DOMDocument('1.0', 'UTF-8');
|
||||
$xml->formatOutput = true;
|
||||
|
||||
$root = $xml->createElement('form_submission');
|
||||
$xml->appendChild($root);
|
||||
|
||||
// Static data
|
||||
$static = $xml->createElement('static');
|
||||
$root->appendChild($static);
|
||||
|
||||
foreach (['name', 'lastname', 'title', 'telno', 'mail', 'apparatsname', 'subject', 'semester', 'dauerapparat'] as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$element = $xml->createElement($field, htmlspecialchars($data[$field]));
|
||||
$static->appendChild($element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data['message'])) {
|
||||
$messageEl = $xml->createElement('message', htmlspecialchars($data['message']));
|
||||
$static->appendChild($messageEl);
|
||||
}
|
||||
|
||||
// Books
|
||||
if (isset($data['books']) && is_array($data['books'])) {
|
||||
$booksNode = $xml->createElement('books');
|
||||
$root->appendChild($booksNode);
|
||||
|
||||
foreach ($data['books'] as $book) {
|
||||
$bookNode = $xml->createElement('book');
|
||||
$booksNode->appendChild($bookNode);
|
||||
|
||||
foreach (['authorname', 'year', 'title', 'signature'] as $field) {
|
||||
$value = isset($book[$field]) ? htmlspecialchars($book[$field]) : '';
|
||||
$fieldNode = $xml->createElement($field, $value);
|
||||
$bookNode->appendChild($fieldNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $xml->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate XML for ELSA form
|
||||
*/
|
||||
function generateELSAXML($data) {
|
||||
$xml = new DOMDocument('1.0', 'UTF-8');
|
||||
$xml->formatOutput = true;
|
||||
|
||||
$root = $xml->createElement('elsa_submission');
|
||||
$xml->appendChild($root);
|
||||
|
||||
// General info
|
||||
$generalInfo = $xml->createElement('general_info');
|
||||
$root->appendChild($generalInfo);
|
||||
|
||||
$generalFields = ['name', 'lastname', 'title', 'mail', 'subject', 'classname',
|
||||
'usage_date_from', 'usage_date_to', 'availability_date'];
|
||||
|
||||
foreach ($generalFields as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$element = $xml->createElement($field, htmlspecialchars($data[$field]));
|
||||
$generalInfo->appendChild($element);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data['message'])) {
|
||||
$messageEl = $xml->createElement('message', htmlspecialchars($data['message']));
|
||||
$generalInfo->appendChild($messageEl);
|
||||
}
|
||||
|
||||
// Media sections
|
||||
$mediaRoot = $xml->createElement('media');
|
||||
$root->appendChild($mediaRoot);
|
||||
|
||||
// Add different media types (monografie, zeitschrift, herausgeber)
|
||||
$mediaTypes = [
|
||||
'monografien' => $data['monografien'] ?? [],
|
||||
'zeitschriftenartikel' => $data['zeitschriftenartikel'] ?? [],
|
||||
'herausgeberwerke' => $data['herausgeberwerke'] ?? []
|
||||
];
|
||||
|
||||
foreach ($mediaTypes as $type => $entries) {
|
||||
if (!empty($entries)) {
|
||||
$section = $xml->createElement($type);
|
||||
$mediaRoot->appendChild($section);
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$entryNode = $xml->createElement('entry');
|
||||
$section->appendChild($entryNode);
|
||||
|
||||
foreach ($entry as $key => $value) {
|
||||
$fieldNode = $xml->createElement($key, htmlspecialchars($value));
|
||||
$entryNode->appendChild($fieldNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $xml->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email with XML attachment
|
||||
* Uses PHP's mail() function or SMTP if configured
|
||||
*/
|
||||
function sendEmail($subject, $xmlContent, $toEmail = null) {
|
||||
$to = $toEmail ?? MAIL_TO;
|
||||
$from = MAIL_FROM;
|
||||
|
||||
if (!MAIL_ENABLED) {
|
||||
// Log instead of sending
|
||||
error_log("==========================================================");
|
||||
error_log("MAIL SENDING DISABLED - Would have sent:");
|
||||
error_log("From: " . $from);
|
||||
error_log("To: " . $to);
|
||||
error_log("Subject: " . $subject);
|
||||
error_log("----------------------------------------------------------");
|
||||
error_log($xmlContent);
|
||||
error_log("==========================================================");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try using SMTP if credentials are configured
|
||||
if (SMTP_USERNAME && SMTP_PASSWORD && class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||
return sendEmailSMTP($subject, $xmlContent, $to, $from);
|
||||
}
|
||||
|
||||
// Fallback to PHP mail()
|
||||
$headers = "From: " . $from . "\r\n";
|
||||
$headers .= "Content-Type: application/xml; charset=UTF-8\r\n";
|
||||
$headers .= "X-Mailer: PHP/" . phpversion();
|
||||
|
||||
return mail($to, $subject, $xmlContent, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email via SMTP using PHPMailer (if available)
|
||||
*/
|
||||
function sendEmailSMTP($subject, $xmlContent, $to, $from) {
|
||||
if (!class_exists('PHPMailer\PHPMailer\PHPMailer')) {
|
||||
error_log("PHPMailer not available, falling back to mail()");
|
||||
return false;
|
||||
}
|
||||
|
||||
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
|
||||
|
||||
try {
|
||||
// Server settings
|
||||
$mail->isSMTP();
|
||||
$mail->Host = SMTP_HOST;
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = SMTP_USERNAME;
|
||||
$mail->Password = SMTP_PASSWORD;
|
||||
$mail->SMTPSecure = SMTP_ENCRYPTION;
|
||||
$mail->Port = SMTP_PORT;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
// Recipients
|
||||
$mail->setFrom($from);
|
||||
$mail->addAddress($to);
|
||||
|
||||
// Content
|
||||
$mail->Subject = $subject;
|
||||
$mail->Body = $xmlContent;
|
||||
$mail->ContentType = 'application/xml';
|
||||
|
||||
$mail->send();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log("Email sending failed: " . $mail->ErrorInfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to URL
|
||||
*/
|
||||
function redirect($url) {
|
||||
header("Location: " . $url);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get POST value with default
|
||||
*/
|
||||
function post($key, $default = '') {
|
||||
return isset($_POST[$key]) ? sanitizeInput($_POST[$key]) : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all POST values matching a pattern (for arrays)
|
||||
*/
|
||||
function postArray($key) {
|
||||
return isset($_POST[$key]) && is_array($_POST[$key]) ?
|
||||
array_map('sanitizeInput', $_POST[$key]) : [];
|
||||
}
|
||||
138
php/index.php
Normal file
138
php/index.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php require_once 'config.php'; ?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>PH Freiburg Bibliothek - Formulare</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="<?php echo STATIC_PATH; ?>/styles.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<div class="header-left">
|
||||
<img class="logo" src="https://www.ph-freiburg.de/_assets/cc3dd7db45300ecc1f3aeed85bda5532/Images/logo-big-blue.svg" alt="PH Freiburg Logo" />
|
||||
<div class="brand">
|
||||
<div class="brand-title">Bibliothek der Pädagogischen Hochschule Freiburg</div>
|
||||
<div class="brand-sub">Hochschulbibliothek · Online-Formulare</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="theme-toggle" class="theme-toggle" aria-label="Switch to dark mode" title="Switch to dark mode">
|
||||
<span class="mdi mdi-theme-light-dark" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<section class="landing-hero">
|
||||
<h1>Willkommen</h1>
|
||||
<p class="hero-subtitle">Bitte wählen Sie den gewünschten Service:</p>
|
||||
</section>
|
||||
|
||||
<div class="service-grid">
|
||||
<a href="semesterapparat.php" class="service-card">
|
||||
<div class="service-icon">
|
||||
<span class="mdi mdi-book-open-page-variant"></span>
|
||||
</div>
|
||||
<h2>Semesterapparat</h2>
|
||||
<p>Antrag für die Einrichtung eines Semesterapparats</p>
|
||||
<div class="service-arrow">
|
||||
<span class="mdi mdi-arrow-right"></span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="elsa.php" class="service-card">
|
||||
<div class="service-icon">
|
||||
<span class="mdi mdi-library-shelves"></span>
|
||||
</div>
|
||||
<h2>ELSA</h2>
|
||||
<p>Elektronischer Semesterapparat</p>
|
||||
<div class="service-arrow">
|
||||
<span class="mdi mdi-arrow-right"></span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<section class="info-section">
|
||||
<div class="card">
|
||||
<h3>Hinweise</h3>
|
||||
<p>
|
||||
Weitere Informationen zu den Semesterapparaten und elektronischen Angeboten finden Sie auf den Seiten der Hochschulbibliothek.
|
||||
</p>
|
||||
<div class="info-links">
|
||||
<a href="https://www.ph-freiburg.de/bibliothek.html" target="_blank" rel="noopener noreferrer">
|
||||
<span class="mdi mdi-open-in-new"></span> Zur Bibliothek
|
||||
</a>
|
||||
<a href="https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate.html" target="_blank" rel="noopener noreferrer">
|
||||
<span class="mdi mdi-open-in-new"></span> Zu den Semesterapparaten
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div id="success-toast" class="toast <?php echo isset($_GET['success']) && $_GET['success'] === 'true' ? '' : 'hidden'; ?>">
|
||||
<div class="toast-icon">
|
||||
<span class="mdi mdi-check-circle"></span>
|
||||
</div>
|
||||
<div class="toast-content">
|
||||
<div class="toast-title">Erfolgreich gesendet</div>
|
||||
<div class="toast-message">Mail wurde geschickt, Sie erhalten demnächst mehr Informationen</div>
|
||||
</div>
|
||||
<button class="toast-close" onclick="hideSuccessToast()" aria-label="Close">
|
||||
<span class="mdi mdi-close"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const STORAGE_KEY = 'theme';
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
|
||||
function setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem(STORAGE_KEY, theme);
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
const label = theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
|
||||
btn.setAttribute('aria-label', label);
|
||||
btn.title = label;
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(saved || (prefersDark ? 'dark' : 'light'));
|
||||
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', () => {
|
||||
const current = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
||||
setTheme(current === 'dark' ? 'light' : 'dark');
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
function hideSuccessToast() {
|
||||
const toast = document.getElementById('success-toast');
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
toast.classList.add('hidden');
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Show toast and auto-hide
|
||||
(function() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.get('success') === 'true') {
|
||||
const toast = document.getElementById('success-toast');
|
||||
setTimeout(() => toast.classList.add('show'), 10);
|
||||
setTimeout(hideSuccessToast, 20000);
|
||||
|
||||
// Clean URL
|
||||
const cleanUrl = window.location.pathname;
|
||||
window.history.replaceState({}, document.title, cleanUrl);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
198
php/semesterapparat.php
Normal file
198
php/semesterapparat.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php require_once 'config.php'; ?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Semesterapparatsantrag</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="<?php echo STATIC_PATH; ?>/styles.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div class="container header-inner">
|
||||
<div class="header-left">
|
||||
<img class="logo" src="https://www.ph-freiburg.de/_assets/cc3dd7db45300ecc1f3aeed85bda5532/Images/logo-big-blue.svg" alt="PH Freiburg Logo" />
|
||||
<div class="brand">
|
||||
<div class="brand-title">Bibliothek der Pädagogischen Hochschule Freiburg</div>
|
||||
<div class="brand-sub">Hochschulbibliothek · Semesterapparate</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="theme-toggle" class="theme-toggle" aria-label="Switch to dark mode" title="Switch to dark mode">
|
||||
<span class="mdi mdi-theme-light-dark" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<section class="card">
|
||||
<h1>Semesterapparatsinformationen</h1>
|
||||
<form method="post" action="submit_semesterapparat.php" class="request-form">
|
||||
<div class="grid-form">
|
||||
<div class="form-field">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" name="name" id="name" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="lastname">Nachname</label>
|
||||
<input type="text" name="lastname" id="lastname" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="title">Titel (optional)</label>
|
||||
<input type="text" name="title" id="title">
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="telno">Telefonnummer</label>
|
||||
<input type="tel" name="telno" id="telno" required>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label for="mail">Email</label>
|
||||
<input type="email" name="mail" id="mail" required>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="apparatsname">Apparatsname</label>
|
||||
<input type="text" name="apparatsname" id="apparatsname" maxlength="40" required>
|
||||
<div id="apparatsname-warning" class="field-info hidden" role="status" aria-live="polite">Name will be changed to keep in line with requirements</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="subject">Fach</label>
|
||||
<select name="subject" id="subject" required>
|
||||
<option value="">-- Auswählen --</option>
|
||||
<option>Biologie</option>
|
||||
<option>Chemie</option>
|
||||
<option>Deutsch</option>
|
||||
<option>Englisch</option>
|
||||
<option>Erziehungswirtschaft</option>
|
||||
<option>Französisch</option>
|
||||
<option>Geographie</option>
|
||||
<option>Geschichte</option>
|
||||
<option>Gesundheitspädagogik</option>
|
||||
<option>Haushalt / Textil</option>
|
||||
<option>Kunst</option>
|
||||
<option>Mathematik / Informatik</option>
|
||||
<option>Medien in der Bildung</option>
|
||||
<option>Musik</option>
|
||||
<option>Philosophie</option>
|
||||
<option>Physik</option>
|
||||
<option>Politikwissenschaft</option>
|
||||
<option>Prorektorat Lehre und Studium</option>
|
||||
<option>Psychologie</option>
|
||||
<option>Soziologie</option>
|
||||
<option>Sport</option>
|
||||
<option>Technik</option>
|
||||
<option>Theologie</option>
|
||||
<option>Wirtschaftslehre</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Semester</label>
|
||||
<div class="inline-controls">
|
||||
<label class="radio"><input type="radio" name="semester_type" value="SoSe" required>Sommer</label>
|
||||
<label class="radio"><input type="radio" name="semester_type" value="WiSe" required>Winter</label>
|
||||
<input type="number" name="semester_year" placeholder="Jahr" required>
|
||||
</div>
|
||||
<div class="inline-controls start" style="margin-top: 0.5rem;">
|
||||
<label class="checkbox"><input type="checkbox" name="dauerapparat" value="true"> Dauerapparat</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Medien</h2>
|
||||
<table id="book-table" class="data-table">
|
||||
<tr>
|
||||
<th>Autorenname</th><th>Jahr/Auflage</th><th>Titel</th><th>Signatur (wenn vorhanden)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="text" name="authorname[]" required></td>
|
||||
<td><input type="text" name="year[]" required></td>
|
||||
<td><input type="text" name="booktitle[]" required></td>
|
||||
<td><input type="text" name="signature[]"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<button type="button" class="btn btn-secondary" onclick="addRow()">+ Medium hinzufügen</button>
|
||||
|
||||
<div class="form-field" style="margin-top: 20px;">
|
||||
<label for="message">Nachricht (optional)</label>
|
||||
<textarea name="message" id="message" rows="4" placeholder="Zusätzliche Anmerkungen oder Hinweise..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-primary">Absenden</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="footer-note">
|
||||
Hinweis: Weitere Informationen zu den Semesterapparaten finden Sie auf den Seiten der Hochschulbibliothek der PH Freiburg.
|
||||
<br>
|
||||
<a href="https://www.ph-freiburg.de/bibliothek.html" target="_blank" rel="noopener noreferrer">Zur Bibliothek</a>
|
||||
<br>
|
||||
<a href="https://www.ph-freiburg.de/bibliothek/lernen/semesterapparate.html" target="_blank" rel="noopener noreferrer">Zu den Semesterapparaten</a>
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
function addRow() {
|
||||
const table = document.getElementById("book-table");
|
||||
const row = table.insertRow(-1);
|
||||
row.innerHTML = `
|
||||
<td><input type="text" name="authorname[]" required></td>
|
||||
<td><input type="text" name="year[]" required></td>
|
||||
<td><input type="text" name="booktitle[]" required></td>
|
||||
<td><input type="text" name="signature[]"></td>
|
||||
`;
|
||||
}
|
||||
|
||||
(function() {
|
||||
const STORAGE_KEY = 'theme';
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
|
||||
function setTheme(theme) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem(STORAGE_KEY, theme);
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
const label = theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode';
|
||||
btn.setAttribute('aria-label', label);
|
||||
btn.title = label;
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(saved || (prefersDark ? 'dark' : 'light'));
|
||||
|
||||
const btn = document.getElementById('theme-toggle');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', () => {
|
||||
const current = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
||||
setTheme(current === 'dark' ? 'light' : 'dark');
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
(function() {
|
||||
function updateWarning() {
|
||||
const last = document.getElementById('lastname');
|
||||
const app = document.getElementById('apparatsname');
|
||||
const warn = document.getElementById('apparatsname-warning');
|
||||
if (!last || !app || !warn) return;
|
||||
const lastLen = (last.value || '').length;
|
||||
const appLen = (app.value || '').length;
|
||||
const threshold = Math.max(0, 37 - lastLen);
|
||||
if (appLen > threshold) {
|
||||
warn.classList.remove('hidden');
|
||||
} else {
|
||||
warn.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
document.addEventListener('input', (e) => {
|
||||
if (e.target && (e.target.id === 'lastname' || e.target.id === 'apparatsname')) {
|
||||
updateWarning();
|
||||
}
|
||||
});
|
||||
document.addEventListener('DOMContentLoaded', updateWarning);
|
||||
updateWarning();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
602
php/static/styles.css
Normal file
602
php/static/styles.css
Normal file
@@ -0,0 +1,602 @@
|
||||
:root {
|
||||
--bg: #f7f8fb;
|
||||
--card-bg: #ffffff;
|
||||
--text: #1f2937;
|
||||
--muted: #6b7280;
|
||||
--primary: #0b7bd6; /* Accessible blue */
|
||||
--primary-600: #0a6ec0;
|
||||
--primary-700: #095fa6;
|
||||
--border: #e5e7eb;
|
||||
--ring: rgba(11, 123, 214, 0.35);
|
||||
--table-head-bg: #f3f4f6;
|
||||
--input-bg: #ffffff;
|
||||
--control-accent: var(--primary);
|
||||
}
|
||||
|
||||
/* Dark theme variables */
|
||||
[data-theme="dark"] {
|
||||
--bg: #0b1220;
|
||||
--card-bg: #121a2a;
|
||||
--text: #e5e7eb;
|
||||
--muted: #9aa4b2;
|
||||
--primary: #5aa1ff;
|
||||
--primary-600: #4b90ea;
|
||||
--primary-700: #3c7ace;
|
||||
--border: #243045;
|
||||
--ring: rgba(90, 161, 255, 0.35);
|
||||
--table-head-bg: #172136;
|
||||
--input-bg: #0f1726;
|
||||
--control-accent: #2a3448;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
html, body { height: 100%; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.site-header {
|
||||
background: var(--card-bg);
|
||||
border-bottom: 1px solid var(--border);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
height: 72px;
|
||||
padding: 14px 0;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
.logo { height: 48px; width: auto; }
|
||||
.brand-title { font-weight: 700; letter-spacing: .2px; }
|
||||
.brand-sub { color: var(--muted); font-size: .95rem; }
|
||||
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
scale: 2;
|
||||
border-radius: 9999px;
|
||||
border: none;
|
||||
background: var(--card-bg);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.theme-toggle:hover { filter: brightness(1.05); }
|
||||
.theme-toggle:focus-visible { outline: none; box-shadow: 0 0 0 4px var(--ring); }
|
||||
|
||||
/* Layout */
|
||||
.container {
|
||||
max-width: 1250px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card-bg);
|
||||
margin: 24px 0;
|
||||
padding: 22px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,.05);
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 14px;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 20px 0 10px;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 14px 0 10px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.table-wrapper { overflow-x: auto; }
|
||||
|
||||
.form-table,
|
||||
.data-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
background: var(--card-bg);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-table::after,
|
||||
.data-table::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.form-table td,
|
||||
.form-table th {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.data-table td,
|
||||
.data-table th {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.form-table tr:last-child td,
|
||||
.data-table tr:last-child td { border-bottom: 0; }
|
||||
|
||||
.data-table th {
|
||||
background: var(--table-head-bg);
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Inputs */
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="tel"],
|
||||
input[type="date"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
background: var(--input-bg);
|
||||
color: var(--text);
|
||||
outline: none;
|
||||
transition: border-color .2s ease, box-shadow .2s ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 4px var(--ring);
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
accent-color: var(--control-accent);
|
||||
}
|
||||
|
||||
.radio { margin-right: 12px; }
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: background-color .2s ease, color .2s ease, border-color .2s ease, transform .02s ease;
|
||||
}
|
||||
|
||||
.btn:active { transform: translateY(1px); }
|
||||
|
||||
.btn-primary {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
.btn-primary:hover { background: var(--primary-600); }
|
||||
.btn-primary:focus { box-shadow: 0 0 0 4px var(--ring); }
|
||||
|
||||
.btn-secondary {
|
||||
background: #e7eef8;
|
||||
color: var(--primary-700);
|
||||
border-color: #cfd9ea;
|
||||
}
|
||||
.btn-secondary:hover { background: #dfe8f6; }
|
||||
.btn-secondary:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
background: #e7eef8;
|
||||
color: var(--muted);
|
||||
}
|
||||
.btn-secondary:disabled:hover {
|
||||
background: #e7eef8;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .btn-secondary {
|
||||
background: #1c2637;
|
||||
color: var(--text);
|
||||
border-color: #2a3852;
|
||||
}
|
||||
[data-theme="dark"] .btn-secondary:hover { background: #1f2b3f; }
|
||||
[data-theme="dark"] .btn-secondary:disabled {
|
||||
opacity: 0.5;
|
||||
background: #1c2637;
|
||||
color: var(--muted);
|
||||
}
|
||||
[data-theme="dark"] .btn-secondary:disabled:hover {
|
||||
background: #1c2637;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.footer-note {
|
||||
margin-top: 18px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.footer-note a { color: var(--primary-700); text-decoration: none; }
|
||||
.footer-note a:hover { text-decoration: underline; }
|
||||
|
||||
/* Static Information grid */
|
||||
.grid-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.form-field label {
|
||||
font-size: 0.9rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.field-info {
|
||||
margin-top: 4px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--primary-700);
|
||||
}
|
||||
[data-theme="dark"] .field-info { color: #a9c8ff; }
|
||||
.hidden { display: none !important; }
|
||||
|
||||
.inline-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.inline-controls.start {
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
.inline-controls input[type="number"] {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Landing page styles */
|
||||
.landing-hero {
|
||||
text-align: center;
|
||||
margin: 40px 0 30px;
|
||||
}
|
||||
.landing-hero h1 {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.hero-subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.service-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
padding: 24px;
|
||||
text-decoration: none;
|
||||
color: var(--text);
|
||||
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.service-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 12px 40px rgba(0,0,0,.1);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
font-size: 3rem;
|
||||
color: var(--primary);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.service-card h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.service-card p {
|
||||
color: var(--muted);
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.service-arrow {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary);
|
||||
opacity: 0;
|
||||
transition: opacity .2s ease, transform .2s ease;
|
||||
}
|
||||
|
||||
.service-card:hover .service-arrow {
|
||||
opacity: 1;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.info-section {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.info-links {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.info-links a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Toast notification */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,.15);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
max-width: 400px;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
transition: opacity .3s ease, transform .3s ease;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.toast-icon {
|
||||
font-size: 1.5rem;
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.toast-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.toast-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
font-size: 0.9rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.toast-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
font-size: 1.2rem;
|
||||
padding: 4px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.toast-close:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 1024px) {
|
||||
.grid-form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.header-inner { padding: 12px 0; height: auto; }
|
||||
.logo { height: 40px; }
|
||||
.form-table td:first-child { width: 40%; }
|
||||
.landing-hero h1 { font-size: 2rem; }
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.grid-form { grid-template-columns: 1fr; }
|
||||
.inline-controls { flex-wrap: wrap; }
|
||||
.toast {
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.data-table + .btn { margin-top: 14px; }
|
||||
|
||||
/* ELSA-specific styles */
|
||||
.legal-notice {
|
||||
background: rgba(11, 123, 214, 0.1);
|
||||
border-left: 4px solid var(--primary);
|
||||
padding: 16px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.legal-notice h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0 0 10px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.legal-notice p {
|
||||
margin: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .legal-notice {
|
||||
background: rgba(90, 161, 255, 0.15);
|
||||
border-left-color: var(--primary);
|
||||
}
|
||||
|
||||
.media-controls {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin: 20px 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.media-section {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.media-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.media-section-header h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.media-table {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.media-table input[type="text"],
|
||||
.media-table input[type="number"] {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
padding: 6px;
|
||||
border-radius: 6px;
|
||||
transition: background-color .2s ease, color .2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: rgba(0,0,0,.05);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .btn-icon:hover {
|
||||
background: rgba(255,255,255,.05);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 8px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Signature validation states */
|
||||
.signature-validating {
|
||||
border-color: #f59e0b !important;
|
||||
background-image: linear-gradient(45deg, rgba(245, 158, 11, 0.1) 25%, transparent 25%, transparent 50%, rgba(245, 158, 11, 0.1) 50%, rgba(245, 158, 11, 0.1) 75%, transparent 75%, transparent);
|
||||
background-size: 20px 20px;
|
||||
animation: signature-loading 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes signature-loading {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: 20px 20px; }
|
||||
}
|
||||
|
||||
.signature-valid {
|
||||
border-color: #10b981 !important;
|
||||
background-color: rgba(16, 185, 129, 0.05);
|
||||
}
|
||||
|
||||
.signature-invalid {
|
||||
border-color: #ef4444 !important;
|
||||
background-color: rgba(239, 68, 68, 0.05);
|
||||
}
|
||||
|
||||
.threshold-exceeded {
|
||||
background-color: rgba(239, 68, 68, 0.08);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .threshold-exceeded {
|
||||
background-color: rgba(239, 68, 68, 0.12);
|
||||
}
|
||||
139
php/submit_elsa.php
Normal file
139
php/submit_elsa.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
require_once 'functions.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
redirect('elsa.php');
|
||||
}
|
||||
|
||||
// Collect general information
|
||||
$name = post('name');
|
||||
$lastname = post('lastname');
|
||||
$title = post('title');
|
||||
$mail = post('mail');
|
||||
$subject = post('subject');
|
||||
$classname = post('classname');
|
||||
$usage_date_from = post('usage_date_from');
|
||||
$usage_date_to = post('usage_date_to');
|
||||
$availability_date = post('availability_date');
|
||||
$message = post('message');
|
||||
|
||||
// Validate required fields
|
||||
if (empty($name) || empty($lastname) || empty($mail) || empty($subject) ||
|
||||
empty($classname) || empty($usage_date_from) || empty($usage_date_to) || empty($availability_date)) {
|
||||
die('Fehler: Alle Pflichtfelder müssen ausgefüllt werden.');
|
||||
}
|
||||
|
||||
// Validate email
|
||||
if (!validateEmail($mail)) {
|
||||
die('Fehler: Ungültige E-Mail-Adresse.');
|
||||
}
|
||||
|
||||
// Collect media data
|
||||
$monografien = [];
|
||||
$zeitschriftenartikel = [];
|
||||
$herausgeberwerke = [];
|
||||
|
||||
// Process Monografie entries
|
||||
if (isset($_POST['monografie_author']) && is_array($_POST['monografie_author'])) {
|
||||
$authors = postArray('monografie_author');
|
||||
$years = postArray('monografie_year');
|
||||
$editions = postArray('monografie_edition');
|
||||
$titles = postArray('monografie_title');
|
||||
$signatures = postArray('monografie_signature');
|
||||
$pagesFrom = postArray('monografie_pages_from');
|
||||
$pagesTo = postArray('monografie_pages_to');
|
||||
|
||||
for ($i = 0; $i < count($authors); $i++) {
|
||||
$monografien[] = [
|
||||
'author' => $authors[$i] ?? '',
|
||||
'year' => $years[$i] ?? '',
|
||||
'edition' => $editions[$i] ?? '',
|
||||
'title' => $titles[$i] ?? '',
|
||||
'signature' => $signatures[$i] ?? '',
|
||||
'pages_from' => $pagesFrom[$i] ?? '',
|
||||
'pages_to' => $pagesTo[$i] ?? ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Process Zeitschriftenartikel entries
|
||||
if (isset($_POST['zeitschrift_author']) && is_array($_POST['zeitschrift_author'])) {
|
||||
$authors = postArray('zeitschrift_author');
|
||||
$years = postArray('zeitschrift_year');
|
||||
$volumes = postArray('zeitschrift_volume');
|
||||
$articleTitles = postArray('zeitschrift_article_title');
|
||||
$journalTitles = postArray('zeitschrift_journal_title');
|
||||
$signatures = postArray('zeitschrift_signature');
|
||||
$pagesFrom = postArray('zeitschrift_pages_from');
|
||||
$pagesTo = postArray('zeitschrift_pages_to');
|
||||
|
||||
for ($i = 0; $i < count($authors); $i++) {
|
||||
$zeitschriftenartikel[] = [
|
||||
'author' => $authors[$i] ?? '',
|
||||
'year' => $years[$i] ?? '',
|
||||
'volume' => $volumes[$i] ?? '',
|
||||
'article_title' => $articleTitles[$i] ?? '',
|
||||
'journal_title' => $journalTitles[$i] ?? '',
|
||||
'signature' => $signatures[$i] ?? '',
|
||||
'pages_from' => $pagesFrom[$i] ?? '',
|
||||
'pages_to' => $pagesTo[$i] ?? ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Process Herausgeberwerk entries
|
||||
if (isset($_POST['herausgeber_publisher']) && is_array($_POST['herausgeber_publisher'])) {
|
||||
$publishers = postArray('herausgeber_publisher');
|
||||
$workTitles = postArray('herausgeber_work_title');
|
||||
$years = postArray('herausgeber_year');
|
||||
$editions = postArray('herausgeber_edition');
|
||||
$articleAuthors = postArray('herausgeber_article_author');
|
||||
$articleTitles = postArray('herausgeber_article_title');
|
||||
$signatures = postArray('herausgeber_signature');
|
||||
$pagesFrom = postArray('herausgeber_pages_from');
|
||||
$pagesTo = postArray('herausgeber_pages_to');
|
||||
|
||||
for ($i = 0; $i < count($publishers); $i++) {
|
||||
$herausgeberwerke[] = [
|
||||
'publisher' => $publishers[$i] ?? '',
|
||||
'work_title' => $workTitles[$i] ?? '',
|
||||
'year' => $years[$i] ?? '',
|
||||
'edition' => $editions[$i] ?? '',
|
||||
'article_author' => $articleAuthors[$i] ?? '',
|
||||
'article_title' => $articleTitles[$i] ?? '',
|
||||
'signature' => $signatures[$i] ?? '',
|
||||
'pages_from' => $pagesFrom[$i] ?? '',
|
||||
'pages_to' => $pagesTo[$i] ?? ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare data for XML generation
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'lastname' => $lastname,
|
||||
'title' => $title,
|
||||
'mail' => $mail,
|
||||
'subject' => $subject,
|
||||
'classname' => $classname,
|
||||
'usage_date_from' => $usage_date_from,
|
||||
'usage_date_to' => $usage_date_to,
|
||||
'availability_date' => $availability_date,
|
||||
'message' => $message,
|
||||
'monografien' => $monografien,
|
||||
'zeitschriftenartikel' => $zeitschriftenartikel,
|
||||
'herausgeberwerke' => $herausgeberwerke
|
||||
];
|
||||
|
||||
// Generate XML
|
||||
$xml = generateELSAXML($data);
|
||||
|
||||
// Send email
|
||||
$emailSent = sendEmail('New ELSA Form Submission', $xml);
|
||||
|
||||
if ($emailSent || !MAIL_ENABLED) {
|
||||
redirect('index.php?success=true');
|
||||
} else {
|
||||
die('Fehler: E-Mail konnte nicht gesendet werden. Bitte versuchen Sie es später erneut.');
|
||||
}
|
||||
80
php/submit_semesterapparat.php
Normal file
80
php/submit_semesterapparat.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
require_once 'functions.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
redirect('semesterapparat.php');
|
||||
}
|
||||
|
||||
// Collect form data
|
||||
$name = post('name');
|
||||
$lastname = post('lastname');
|
||||
$title = post('title');
|
||||
$telno = post('telno');
|
||||
$mail = post('mail');
|
||||
$apparatsname = post('apparatsname');
|
||||
$subject = post('subject');
|
||||
$semester_type = post('semester_type');
|
||||
$semester_year = post('semester_year');
|
||||
$dauerapparat = isset($_POST['dauerapparat']) ? 'true' : 'false';
|
||||
$message = post('message');
|
||||
|
||||
// Validate required fields
|
||||
if (empty($name) || empty($lastname) || empty($telno) || empty($mail) ||
|
||||
empty($apparatsname) || empty($subject) || empty($semester_type) || empty($semester_year)) {
|
||||
die('Fehler: Alle Pflichtfelder müssen ausgefüllt werden.');
|
||||
}
|
||||
|
||||
// Validate email
|
||||
if (!validateEmail($mail)) {
|
||||
die('Fehler: Ungültige E-Mail-Adresse.');
|
||||
}
|
||||
|
||||
// Collect book data
|
||||
$authornames = postArray('authorname');
|
||||
$years = postArray('year');
|
||||
$booktitles = postArray('booktitle');
|
||||
$signatures = postArray('signature');
|
||||
|
||||
// Validate at least one book
|
||||
if (empty($authornames) || count($authornames) === 0) {
|
||||
die('Fehler: Mindestens ein Medium muss angegeben werden.');
|
||||
}
|
||||
|
||||
// Build books array
|
||||
$books = [];
|
||||
for ($i = 0; $i < count($authornames); $i++) {
|
||||
$books[] = [
|
||||
'authorname' => $authornames[$i] ?? '',
|
||||
'year' => $years[$i] ?? '',
|
||||
'title' => $booktitles[$i] ?? '',
|
||||
'signature' => $signatures[$i] ?? ''
|
||||
];
|
||||
}
|
||||
|
||||
// Prepare data for XML generation
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'lastname' => $lastname,
|
||||
'title' => $title,
|
||||
'telno' => $telno,
|
||||
'mail' => $mail,
|
||||
'apparatsname' => $apparatsname,
|
||||
'subject' => $subject,
|
||||
'semester' => $semester_type . ' ' . $semester_year,
|
||||
'dauerapparat' => $dauerapparat,
|
||||
'message' => $message,
|
||||
'books' => $books
|
||||
];
|
||||
|
||||
// Generate XML
|
||||
$xml = generateXML($data);
|
||||
|
||||
// Send email
|
||||
$emailSent = sendEmail('Antrag für neuen Semesterapparat', $xml);
|
||||
|
||||
if ($emailSent || !MAIL_ENABLED) {
|
||||
redirect('index.php?success=true');
|
||||
} else {
|
||||
die('Fehler: E-Mail konnte nicht gesendet werden. Bitte versuchen Sie es später erneut.');
|
||||
}
|
||||
Reference in New Issue
Block a user