This commit is contained in:
2025-11-30 02:51:15 +01:00
parent 3ebfb8c7f6
commit 2fb5093c7f
9 changed files with 217 additions and 205 deletions

View File

@@ -0,0 +1,163 @@
<?php
// /api/v1/browser.quick.test.php
declare(strict_types=1);
session_start();
// DB einbinden Pfad abhängig von deinem Setup, aktuell:
require $_SERVER['DOCUMENT_ROOT']. '/../config/db.php'; // stellt $pdo (PDO) bereit
header('Content-Type: application/json; charset=utf-8');
// ---------------------------------------------------------------------
// 1. JSON einlesen
// ---------------------------------------------------------------------
$raw = file_get_contents('php://input');
$data = json_decode($raw, true);
if (!is_array($data)) {
http_response_code(400);
echo json_encode([
'ok' => false,
'error' => 'Invalid JSON payload',
]);
exit;
}
// ---------------------------------------------------------------------
// 2. User / Session ermitteln
// ---------------------------------------------------------------------
$userId = $_SESSION['user_id'] ?? null; // abhängig von deiner Login-Implementierung
$isLoggedIn = $userId ? 1 : 0;
$sessionId = session_id() ?: null;
$ipAddress = $_SERVER['REMOTE_ADDR'] ?? null;
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
// ---------------------------------------------------------------------
// 3. Grobe Auswertung aus dem Report (optional)
// ---------------------------------------------------------------------
$modeRequested = $data['mode_requested'] ?? 'unknown';
$meta = $data['meta'] ?? [];
// Browser/OS-Parsing kannst du später ergänzen
$browserName = null;
$browserVersion = null;
$osName = null;
$osVersion = null;
// Gesamtmenge geschriebener/verifizierter Bytes aggregieren
$measuredBytes = 0;
if (!empty($data['quick']) && is_array($data['quick'])) {
$measuredBytes += (int)($data['quick']['size_bytes'] ?? 0);
}
if (!empty($data['benchmark']) && is_array($data['benchmark'])) {
$measuredBytes += (int)($data['benchmark']['size_bytes'] ?? 0);
}
if (!empty($data['writeverify']) && is_array($data['writeverify'])) {
$measuredBytes += (int)($data['writeverify']['total_bytes'] ?? 0);
}
// Kapazitätsstatus vorerst neutral
$capacityStatus = 'unknown';
// Volume-/Stick-Daten aktuell noch nicht separat:
$volumeLabel = null;
$manufacturer = null;
$modelName = null;
$usbType = null;
$filesystem = null;
// advertised_capacity_bytes kennen wir im Browser noch nicht:
$advCapacityBytes = null;
// test_report_json = kompletter Report
$testReportJson = $raw; // direkt als JSON-String speichern
// ---------------------------------------------------------------------
// 4. Insert in web_quicktests
// ---------------------------------------------------------------------
try {
$sql = "
INSERT INTO web_quicktests (
user_id,
is_logged_in,
usb_device_id,
browser_name,
browser_version,
os_name,
os_version,
volume_label,
manufacturer,
model_name,
usb_type,
advertised_capacity_bytes,
measured_capacity_bytes,
capacity_status,
filesystem,
test_report_json,
ip_address,
session_id
)
VALUES (
:user_id,
:is_logged_in,
:usb_device_id,
:browser_name,
:browser_version,
:os_name,
:os_version,
:volume_label,
:manufacturer,
:model_name,
:usb_type,
:adv_capacity,
:measured_capacity,
:capacity_status,
:filesystem,
CAST(:test_report_json AS JSON),
:ip_address,
:session_id
)
";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'user_id' => $userId,
'is_logged_in' => $isLoggedIn,
'usb_device_id' => null, // Browser-Test ist erstmal nicht an gespeicherten Stick gekoppelt
'browser_name' => $browserName,
'browser_version' => $browserVersion,
'os_name' => $osName,
'os_version' => $osVersion,
'volume_label' => $volumeLabel,
'manufacturer' => $manufacturer,
'model_name' => $modelName,
'usb_type' => $usbType,
'adv_capacity' => $advCapacityBytes,
'measured_capacity' => $measuredBytes ?: null,
'capacity_status' => $capacityStatus,
'filesystem' => $filesystem,
'test_report_json' => $testReportJson,
'ip_address' => $ipAddress,
'session_id' => $sessionId,
]);
$id = (int)$pdo->lastInsertId();
echo json_encode([
'ok' => true,
'id' => $id,
]);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode([
'ok' => false,
'error' => 'DB error',
// 'debug' => $e->getMessage(), // nur zum Debuggen aktivieren
]);
}

View File

@@ -0,0 +1,316 @@
<?php
// api/v1/quickcheck.php
/**
* Diese Funktion wird von api/index.php aufgerufen.
* Sie liest die Eingaben, prüft Seriennummer + VID, und gibt ein Array zurück,
* das dann als JSON ausgegeben wird.
*/
function quickcheck_handle_request(): array
{
// JSON Body hat Priorität
$source = quickcheck_get_input();
$vid = isset($source['vid']) ? trim((string)$source['vid']) : '';
$pid = isset($source['pid']) ? trim((string)$source['pid']) : '';
$manufacturer = isset($source['manufacturer']) ? trim((string)$source['manufacturer']) : '';
$serial = isset($source['serial']) ? trim((string)$source['serial']) : '';
if ($serial === '') {
http_response_code(400);
return [
'success' => false,
'error' => 'Missing required parameter: serial',
];
}
// Mini-VID-Datenbank (kannst du später aus Datei/DB laden)
$VID_DB = [
'0781' => 'SanDisk Corp.',
'0951' => 'Kingston Technology',
'054C' => 'Sony Corp.',
'1B1C' => 'Corsair',
'13FE' => 'Phison Electronics',
'8564' => 'Transcend Information, Inc.',
'090C' => 'Silicon Motion, Inc.',
'174C' => 'ASMedia Technology',
'0BC2' => 'Seagate',
// ... nach Bedarf ergänzen
];
$vendorInfo = quickcheck_lookup_vendor($vid, $VID_DB);
$serialAnalysis = quickcheck_analyze_serial($serial);
$consistencyInfo = quickcheck_evaluate_consistency($vendorInfo['vendor'] ?? null, $manufacturer, $serialAnalysis);
// Gesamtrating
$rating = 'ok';
if ($serialAnalysis['category'] === 'invalid') {
$rating = 'invalid';
} elseif ($serialAnalysis['category'] === 'very_suspicious' || $consistencyInfo['manufacturer_match'] === 'mismatch') {
$rating = 'suspicious';
} elseif ($serialAnalysis['category'] === 'suspicious') {
$rating = 'needs_review';
}
return [
'success' => true,
'rating' => $rating,
'input' => [
'vid' => $vid,
'pid' => $pid,
'manufacturer' => $manufacturer,
'serial' => $serial,
],
'vendor_detected' => $vendorInfo,
'serial_analysis' => $serialAnalysis,
'consistency' => $consistencyInfo,
'messages' => [
'de' => [
'Hinweis: Diese Prüfung kann keine Echtheit garantieren, sondern bewertet nur Plausibilität und Auffälligkeiten.',
],
],
];
}
/**
* Eingaben lesen: JSON-Body > POST > GET
*/
function quickcheck_get_input(): array
{
$contentType = $_SERVER['CONTENT_TYPE'] ?? $_SERVER['HTTP_CONTENT_TYPE'] ?? '';
$contentType = strtolower(trim(explode(';', $contentType)[0]));
if ($contentType === 'application/json') {
$raw = file_get_contents('php://input');
if ($raw !== false && $raw !== '') {
$data = json_decode($raw, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
return $data;
}
}
}
if (!empty($_POST)) {
return $_POST;
}
if (!empty($_GET)) {
return $_GET;
}
return [];
}
/**
* VID normalisieren + Lookup
*/
function quickcheck_normalize_vid(string $vid): ?string
{
$vid = strtoupper(trim($vid));
$vid = preg_replace('/^0X/i', '', $vid);
if ($vid === '' || !preg_match('/^[0-9A-F]{1,4}$/', $vid)) {
return null;
}
return str_pad($vid, 4, '0', STR_PAD_LEFT);
}
function quickcheck_lookup_vendor(?string $vid, array $VID_DB): array
{
if (!$vid) {
return [
'vid' => null,
'found' => false,
'vendor' => null,
'confidence' => 0,
];
}
$norm = quickcheck_normalize_vid($vid);
if (!$norm) {
return [
'vid' => $vid,
'found' => false,
'vendor' => null,
'confidence' => 0,
'issue' => 'Invalid VID format',
];
}
if (isset($VID_DB[$norm])) {
return [
'vid' => $norm,
'found' => true,
'vendor' => $VID_DB[$norm],
'confidence' => 1.0,
];
}
return [
'vid' => $norm,
'found' => false,
'vendor' => null,
'confidence' => 0.2,
];
}
/**
* Seriennummer grob analysieren (Plausibilität)
*/
function quickcheck_analyze_serial(string $serial): array
{
$serial = trim($serial);
$length = strlen($serial);
$issues = [];
$score = 100;
if ($length === 0) {
return [
'serial' => $serial,
'length' => 0,
'issues' => ['empty'],
'score' => 0,
'category' => 'invalid',
];
}
if ($length < 4) {
$issues[] = 'too_short_critical';
$score -= 60;
} elseif ($length < 8) {
$issues[] = 'short_suspicious';
$score -= 30;
}
if ($length > 32) {
$issues[] = 'very_long';
$score -= 10;
}
if (quickcheck_is_all_same_char($serial)) {
$issues[] = 'all_same_char';
$score -= 50;
}
$simplePatterns = [
'000000', '00000000', '000000000000',
'111111', '123456', '12345678', 'ABCDEF', 'AABBCC'
];
if (in_array(strtoupper($serial), $simplePatterns, true)) {
$issues[] = 'simple_pattern';
$score -= 40;
}
if (quickcheck_is_simple_sequence($serial)) {
$issues[] = 'sequence_pattern';
$score -= 25;
}
$isNumeric = preg_match('/^[0-9]+$/', $serial) === 1;
$isAlpha = preg_match('/^[A-Za-z]+$/', $serial) === 1;
$isHex = preg_match('/^[0-9A-Fa-f]+$/', $serial) === 1;
$isAlnum = preg_match('/^[A-Za-z0-9]+$/', $serial) === 1;
if ($isNumeric) {
$issues[] = 'numeric_only';
$score -= 10;
} elseif ($isAlpha) {
$issues[] = 'letters_only';
$score -= 10;
}
if ($isHex && !$isNumeric && $length >= 8 && $length <= 24) {
$issues[] = 'hex_pattern_plausible';
$score += 5;
}
if ($isAlnum && !$isNumeric && !$isAlpha && $length >= 8) {
$issues[] = 'alnum_mixed_plausible';
$score += 5;
}
if ($score > 100) $score = 100;
if ($score < 0) $score = 0;
if ($length === 0) {
$category = 'invalid';
} elseif ($score >= 80) {
$category = 'plausible';
} elseif ($score >= 50) {
$category = 'suspicious';
} else {
$category = 'very_suspicious';
}
return [
'serial' => $serial,
'length' => $length,
'issues' => array_values(array_unique($issues)),
'score' => $score,
'category' => $category,
];
}
function quickcheck_is_all_same_char(string $s): bool
{
return strlen($s) > 1 && preg_match('/^(.)\1+$/', $s) === 1;
}
function quickcheck_is_simple_sequence(string $s): bool
{
$seqs = [
'123456', '1234567', '12345678', '234567', '345678',
'ABCDEFG', 'ABCDEF', 'ABCDE'
];
$ls = strtoupper($s);
foreach ($seqs as $pattern) {
if (strpos($ls, $ls) !== false && strpos($ls, $pattern) !== false) {
return true;
}
}
return false;
}
/**
* Herstellerangabe vs. Vendor-Name bewerten
*/
function quickcheck_evaluate_consistency(?string $vendorName, string $userManufacturer, array $serialAnalysis): array
{
$vendorName = $vendorName ? trim($vendorName) : '';
$userManufacturer = trim($userManufacturer);
$matchStatus = 'unknown';
$notes = [];
if ($vendorName !== '' && $userManufacturer !== '') {
$v = mb_strtolower($vendorName);
$u = mb_strtolower($userManufacturer);
if (strpos($v, $u) !== false || strpos($u, $v) !== false) {
$matchStatus = 'match';
$notes[] = 'Herstellerangabe passt zur ermittelten Vendor-ID.';
} else {
$matchStatus = 'mismatch';
$notes[] = 'Herstellerangabe weicht von der Vendor-ID ab.';
}
} elseif ($vendorName !== '') {
$notes[] = 'Hersteller über Vendor-ID bekannt, aber keine Herstellerangabe des Nutzers.';
} elseif ($userManufacturer !== '') {
$notes[] = 'Hersteller vom Nutzer angegeben, aber keine oder unbekannte Vendor-ID.';
} else {
$notes[] = 'Keine Herstellerinformationen vorhanden.';
}
$ratingHint = 'neutral';
if ($serialAnalysis['category'] === 'very_suspicious' || $matchStatus === 'mismatch') {
$ratingHint = 'suspicious';
} elseif ($serialAnalysis['category'] === 'plausible' && $matchStatus === 'match') {
$ratingHint = 'good';
}
return [
'manufacturer_match' => $matchStatus,
'notes' => $notes,
'consistency_hint' => $ratingHint,
];
}