Upload project smart drop point

This commit is contained in:
Lili Hacika Putri 2026-07-27 11:15:54 +07:00
commit 5cb1f8cf10
402 changed files with 3981 additions and 0 deletions

15
smart-drop-point/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}

View File

@ -0,0 +1,141 @@
:root{
--bg: #0b1220;
--panel: rgba(255,255,255,.06);
--panel2: rgba(255,255,255,.08);
--border: rgba(255,255,255,.12);
--text: rgba(255,255,255,.92);
--muted: rgba(255,255,255,.70);
--accent: #7c3aed;
}
body{
background: radial-gradient(1200px 700px at 10% 10%, rgba(124,58,237,.35), transparent 60%),
radial-gradient(900px 600px at 90% 20%, rgba(34,197,94,.22), transparent 55%),
var(--bg);
color: var(--text);
}
.app{ display:flex; min-height:100vh; }
.sidebar{
width: 280px;
padding: 18px;
background: rgba(255,255,255,.04);
border-right: 1px solid var(--border);
backdrop-filter: blur(14px);
}
.brand{ display:flex; gap:12px; align-items:center; }
.brand-badge{
width:44px; height:44px; border-radius:14px;
display:grid; place-items:center;
background: linear-gradient(135deg, rgba(124,58,237,.9), rgba(34,197,94,.7));
box-shadow: 0 10px 30px rgba(0,0,0,.25);
}
.brand-title{ font-weight:800; letter-spacing:.3px; }
.brand-sub{ color: var(--muted); font-size:.86rem; margin-top:-2px; }
.nav-link{
color: var(--muted);
border-radius: 14px;
padding: 10px 12px;
margin-bottom: 6px;
border: 1px solid transparent;
}
.nav-link:hover{
color: var(--text);
background: var(--panel);
border-color: var(--border);
}
.nav-link.active{
color: var(--text);
background: linear-gradient(135deg, rgba(124,58,237,.22), rgba(34,197,94,.12));
border-color: rgba(124,58,237,.25);
}
.nav-divider{ height:1px; background: var(--border); margin: 10px 0; }
.sidebar-footer{
margin-top: auto;
padding-top: 14px;
border-top: 1px solid var(--border);
}
.main{ flex:1; display:flex; flex-direction:column; }
.topbar{
display:flex; justify-content:space-between; align-items:center;
padding: 18px 22px;
}
.topbar-pill{
display:inline-flex; align-items:center; gap:8px;
padding: 8px 12px;
border-radius: 999px;
background: var(--panel);
border: 1px solid var(--border);
color: var(--muted);
}
.topbar-user{ display:flex; gap:10px; align-items:center; }
.avatar{
width:38px; height:38px; border-radius: 14px;
display:grid; place-items:center;
background: var(--panel2);
border:1px solid var(--border);
font-weight:700;
}
.content{ padding: 0 22px 28px; }
.card-glass{
background: var(--panel);
border: 1px solid var(--border);
border-radius: 18px;
backdrop-filter: blur(14px);
box-shadow: 0 20px 55px rgba(0,0,0,.25);
}
.form-control, .form-select{
background: rgba(255,255,255,.05) !important;
border: 1px solid var(--border) !important;
color: var(--text) !important;
border-radius: 14px !important;
}
.form-control::placeholder{ color: rgba(255,255,255,.45); }
.btn-accent{
background: linear-gradient(135deg, rgba(124,58,237,.95), rgba(34,197,94,.75));
border: none;
border-radius: 14px;
}
/* =========================================================
FIX TABLE TEXT (BIAR TULISANNYA GA GELAP)
========================================================= */
.table{
color: var(--text) !important;
}
.table thead th{
color: rgba(255,255,255,.90) !important;
border-bottom-color: var(--border) !important;
}
.table td, .table th{
border-top-color: var(--border) !important;
color: rgba(255,255,255,.90) !important;
}
/* bootstrap kadang bikin .text-muted jadi gelap */
.text-muted{
color: rgba(255,255,255,.78) !important;
}
/* hover biar makin jelas */
.table-hover tbody tr:hover td,
.table-hover tbody tr:hover th{
color: rgba(255,255,255,1) !important;
}
/* supaya baris table-dark ga override warna */
.table-dark{
--bs-table-color: rgba(255,255,255,.90);
--bs-table-bg: transparent;
--bs-table-border-color: rgba(255,255,255,.12);
--bs-table-hover-color: #fff;
--bs-table-hover-bg: rgba(255,255,255,.06);
}

View File

@ -0,0 +1,31 @@
<?php
$DB_HOST = "localhost";
$DB_USER = "root";
$DB_PASS = "";
$DB_NAME = "smart_drop_point";
// =======================
// KONEK DATABASE
// =======================
$conn = new mysqli(
$DB_HOST,
$DB_USER,
$DB_PASS,
$DB_NAME
);
// =======================
// CEK ERROR
// =======================
if ($conn->connect_error) {
die("Koneksi DB gagal: " . $conn->connect_error);
}
// =======================
// UTF8
// =======================
$conn->set_charset("utf8mb4");
?>

View File

@ -0,0 +1,4 @@
<?php
header("Location: public/");
exit;
?>

View File

@ -0,0 +1,7 @@
</section>
</main>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Smart Drop Point</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<link href="/smart-drop-point/assets/style.css" rel="stylesheet">
</head>
<body>
<div class="app">

View File

@ -0,0 +1,65 @@
<?php
$current = basename($_SERVER['PHP_SELF']);
if (!function_exists('active')) {
function active($name, $current) {
return $name === $current ? "active" : "";
}
}
?>
<aside class="sidebar">
<div class="brand">
<div class="brand-badge"><i class="bi bi-box-seam"></i></div>
<div>
<div class="brand-title">Smart Drop Point</div>
<div class="brand-sub">Monitoring & Auth Resi</div>
</div>
</div>
<nav class="nav flex-column mt-3">
<a class="nav-link <?= active('index.php', $current) ?>" href="/smart-drop-point/public/index.php">
<i class="bi bi-speedometer2 me-2"></i>Dashboard
</a>
<a class="nav-link <?= active('resi.php', $current) ?>" href="/smart-drop-point/public/resi.php">
<i class="bi bi-upc-scan me-2"></i>Data Resi
</a>
<a class="nav-link <?= active('log.php', $current) ?>" href="/smart-drop-point/public/log.php">
<i class="bi bi-clock-history me-2"></i>Log Akses
</a>
<div class="nav-divider"></div>
<a class="nav-link <?= active('resi_add.php', $current) ?>" href="/smart-drop-point/public/resi_add.php">
<i class="bi bi-plus-circle me-2"></i>Tambah Resi
</a>
<a class="nav-link <?= active('upload_barcode.php', $current) ?>" href="/smart-drop-point/public/upload_barcode.php">
<i class="bi bi-cloud-arrow-up me-2"></i>Upload Foto Barcode (Mock)
</a>
</nav>
<div class="sidebar-footer">
<div class="small text-muted">TA: Smart Pickup/Drop Point IoT</div>
</div>
</aside>
<main class="main">
<header class="topbar">
<div class="topbar-left">
</div>
<div class="topbar-right">
<div class="topbar-user">
<div class="avatar">TA</div>
<div>
<div class="fw-semibold">Monitoring</div>
<div class="small text-muted">ESP32-CAM + Barcode</div>
</div>
</div>
</div>
</header>
<section class="content">

View File

@ -0,0 +1,338 @@
#include "esp_camera.h"
#include <WiFi.h>
#include <WiFiClient.h>
// =======================
// WIFI
// =======================
const char* ssid = "P nyoman";
const char* password = "123456789";
// =======================
// SERVER
// =======================
const char* serverHost = "192.168.1.5";
const int serverPort = 80;
const char* serverPath = "/smart-drop-point/public/api/upload_cam.php";
// =======================
// RELAY + LED
// =======================
#define RELAY_PIN 13
#define LED_MERAH 12
#define LED_HIJAU 14
// =======================
// AI THINKER CAMERA PIN
// =======================
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// =======================
// CAMERA INIT
// =======================
bool initCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 15;
config.fb_count = 1;
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init gagal: 0x%x\n", err);
return false;
}
Serial.println("Camera OK");
return true;
}
// =======================
// WIFI CONNECT
// =======================
bool connectWiFi() {
Serial.println("CONNECT WIFI");
WiFi.begin(ssid, password);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 30) {
delay(500);
Serial.print(".");
retry++;
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi Connected");
Serial.println(WiFi.localIP());
return true;
}
Serial.println("WiFi gagal");
return false;
}
// =======================
// CAPTURE FOTO
// =======================
camera_fb_t* capturePhoto() {
Serial.println("CAPTURE FOTO");
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Capture gagal");
return NULL;
}
Serial.println("Foto berhasil");
return fb;
}
// =======================
// UPLOAD FOTO
// =======================
String uploadPhoto(camera_fb_t *fb) {
Serial.println("UPLOAD FOTO");
WiFiClient client;
if (!client.connect(serverHost, serverPort)) {
Serial.println("Server gagal connect");
return "CONNECT_FAILED";
}
String boundary = "----ESP32CAM";
String head = "";
head += "--" + boundary + "\r\n";
head += "Content-Disposition: form-data; name=\"foto\"; filename=\"capture.jpg\"\r\n";
head += "Content-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--" + boundary + "--\r\n";
uint32_t contentLength =
head.length() +
fb->len +
tail.length();
client.print(
String("POST ") +
serverPath +
" HTTP/1.1\r\n"
);
client.print(
String("Host: ") +
serverHost +
"\r\n"
);
client.print("Connection: close\r\n");
client.print(
String("Content-Type: multipart/form-data; boundary=") +
boundary +
"\r\n"
);
client.print(
String("Content-Length: ") +
contentLength +
"\r\n\r\n"
);
client.print(head);
client.write(fb->buf, fb->len);
client.print(tail);
String response = "";
unsigned long timeout = millis();
while (millis() - timeout < 10000) {
while (client.available()) {
char c = client.read();
response += c;
timeout = millis();
}
if (!client.connected()) {
break;
}
delay(10);
}
client.stop();
Serial.println("RESPONSE:");
Serial.println(response);
return response;
}
// =======================
// SETUP
// =======================
void setup() {
Serial.begin(115200);
delay(2000);
// =======================
// PIN MODE
// =======================
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_MERAH, OUTPUT);
pinMode(LED_HIJAU, OUTPUT);
// =======================
// AWAL TERKUNCI
// =======================
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_MERAH, LOW);
digitalWrite(LED_HIJAU, LOW);
Serial.println("ESP32 START");
// =======================
// CAMERA
// =======================
if (!initCamera()) {
return;
}
// =======================
// WIFI
// =======================
if (!connectWiFi()) {
return;
}
// =======================
// FOTO
// =======================
camera_fb_t *fb = capturePhoto();
if (!fb) {
return;
}
// =======================
// UPLOAD
// =======================
String response = uploadPhoto(fb);
esp_camera_fb_return(fb);
// =======================
// CEK VALID
// =======================
if (response.indexOf("VALID") >= 0) {
Serial.println("RESI VALID");
digitalWrite(LED_HIJAU, HIGH);
digitalWrite(LED_MERAH, LOW);
// BUKA SOLENOID
digitalWrite(RELAY_PIN, LOW);
delay(5000);
// KUNCI LAGI
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_HIJAU, LOW);
} else {
Serial.println("RESI TIDAK VALID");
digitalWrite(LED_MERAH, HIGH);
delay(3000);
digitalWrite(LED_MERAH, LOW);
digitalWrite(RELAY_PIN, HIGH);
}
Serial.println("SELESAI");
}
void loop() {
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,391 @@
```php
<?php
ob_clean();
ob_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once __DIR__ . '/../../config/db.php';
date_default_timezone_set("Asia/Jakarta");
header("Content-Type: application/json; charset=utf-8");
http_response_code(200);
// =======================
// DEBUG FILE
// =======================
$debugFile = __DIR__ . "/debug.txt";
function debugLog($text) {
global $debugFile;
file_put_contents(
$debugFile,
date("H:i:s") . " - " . $text . PHP_EOL,
FILE_APPEND
);
}
debugLog("REQUEST MASUK");
// =======================
// FOLDER UPLOAD
// =======================
$uploadDir = __DIR__ . '/../../uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
debugLog("FOLDER UPLOAD DIBUAT");
}
// =======================
// CEK FILE
// =======================
if (!isset($_FILES['foto'])) {
debugLog("FILE FOTO TIDAK ADA");
echo json_encode([
"ok" => false,
"message" => "File foto tidak ada"
], JSON_UNESCAPED_SLASHES);
ob_end_flush();
exit;
}
$f = $_FILES['foto'];
debugLog("FILE FOTO TERDETEKSI");
// =======================
// ERROR UPLOAD
// =======================
if ($f['error'] !== UPLOAD_ERR_OK) {
debugLog("UPLOAD ERROR: " . $f['error']);
echo json_encode([
"ok" => false,
"message" => "Upload error"
], JSON_UNESCAPED_SLASHES);
ob_end_flush();
exit;
}
// =======================
// VALIDASI EXTENSION
// =======================
$ext = strtolower(pathinfo($f['name'], PATHINFO_EXTENSION));
if ($ext == '') {
$ext = 'jpg';
}
$allowed = ['jpg', 'jpeg', 'png'];
if (!in_array($ext, $allowed)) {
debugLog("FORMAT FILE TIDAK VALID");
echo json_encode([
"ok" => false,
"message" => "Format file tidak valid"
], JSON_UNESCAPED_SLASHES);
ob_end_flush();
exit;
}
// =======================
// SIMPAN FILE
// =======================
$filename =
"cam_" .
date("Ymd_His") .
"_" .
rand(100,999) .
"." .
$ext;
$targetPath = $uploadDir . $filename;
if (!move_uploaded_file($f['tmp_name'], $targetPath)) {
debugLog("GAGAL SIMPAN FILE");
echo json_encode([
"ok" => false,
"message" => "Gagal menyimpan file"
], JSON_UNESCAPED_SLASHES);
ob_end_flush();
exit;
}
debugLog("FILE BERHASIL DISIMPAN");
// =======================
// ZBAR
// =======================
$resi = null;
$out = "";
$zbarPath =
'C:\\Program Files (x86)\\ZBar\\bin\\zbarimg.exe';
if (file_exists($zbarPath)) {
debugLog("ZBAR DITEMUKAN");
$cmd =
'"' . $zbarPath . '" ' .
escapeshellarg($targetPath) .
' 2>&1';
debugLog("JALANKAN ZBAR");
$out = shell_exec($cmd);
debugLog("HASIL ZBAR: " . $out);
if ($out === null) {
$out = "";
}
$lines = preg_split(
"/\r\n|\n|\r/",
trim($out)
);
foreach ($lines as $line) {
if (
preg_match(
'/^CODE-128:(.+)$/',
trim($line),
$m
)
) {
$resi = trim($m[1]);
debugLog(
"BARCODE CODE128 TERBACA: " . $resi
);
break;
}
}
} else {
debugLog("ZBAR TIDAK DITEMUKAN");
}
// =======================
// OCR FALLBACK
// =======================
if ($resi === null || $resi === "") {
debugLog("ZBAR GAGAL -> COBA OCR");
$ocrPath =
'C:\\Program Files\\Tesseract-OCR\\tesseract.exe';
if (file_exists($ocrPath)) {
$cmdOCR =
'"' . $ocrPath . '" ' .
escapeshellarg($targetPath) .
' stdout 2>&1';
debugLog("JALANKAN OCR");
$ocrText = shell_exec($cmdOCR);
debugLog("HASIL OCR ASLI: " . $ocrText);
if ($ocrText !== null) {
// =======================
// BERSIHKAN OCR
// =======================
$ocrText = strtoupper($ocrText);
$ocrText = preg_replace(
'/[^A-Z0-9]/',
' ',
$ocrText
);
debugLog(
"HASIL OCR BERSIH: " . $ocrText
);
// =======================
// CARI FORMAT RESI
// =======================
if (
preg_match(
'/([A-Z]{1,5}[0-9]{6,}|[0-9]{10,})/',
$ocrText,
$m
)
) {
$resi = trim($m[0]);
debugLog(
"OCR BERHASIL BACA RESI: " .
$resi
);
} else {
debugLog(
"OCR TIDAK MENEMUKAN RESI"
);
}
}
} else {
debugLog(
"TESSERACT OCR TIDAK DITEMUKAN"
);
}
}
// =======================
// VALIDASI RESI
// =======================
$status = "gagal";
$pesan = "Barcode / OCR tidak terbaca.";
$openLock = false;
if ($resi !== null && $resi !== "") {
debugLog("CEK RESI DATABASE");
$pesan = "Resi tidak terdaftar.";
$stmt = $conn->prepare(
"SELECT 1 FROM resi WHERE nomor_resi = ? LIMIT 1"
);
if ($stmt) {
$stmt->bind_param("s", $resi);
$stmt->execute();
$result = $stmt->get_result();
if (
$result &&
$result->num_rows > 0
) {
$status = "berhasil";
$pesan =
"Resi valid, akses dibuka.";
$openLock = true;
debugLog("RESI VALID");
} else {
debugLog(
"RESI TIDAK TERDAFTAR"
);
}
} else {
debugLog("QUERY RESI GAGAL");
}
}
// =======================
// SIMPAN LOG
// =======================
$fotoPathUrl =
"/smart-drop-point/uploads/" .
$filename;
$nomorResiForLog = $resi ?? "-";
$stmt2 = $conn->prepare("
INSERT INTO log_akses
(
nomor_resi,
status,
pesan,
foto_path,
created_at
)
VALUES (?, ?, ?, ?, NOW())
");
if ($stmt2) {
$stmt2->bind_param(
"ssss",
$nomorResiForLog,
$status,
$pesan,
$fotoPathUrl
);
$stmt2->execute();
debugLog("LOG BERHASIL DISIMPAN");
} else {
debugLog("GAGAL SIMPAN LOG");
}
// =======================
// RESPONSE FINAL
// =======================
$response = [
"ok" => true,
"resi" => $resi,
"status" => $status,
"pesan" => $pesan,
"open_lock" => $openLock,
"foto_path" => $fotoPathUrl
];
debugLog("KIRIM RESPONSE JSON");
echo json_encode(
$response,
JSON_UNESCAPED_SLASHES
);
flush();
ob_end_flush();
debugLog("SELESAI");
exit;
?>
```

View File

@ -0,0 +1,12 @@
<?php
include "../config/db.php";
$data=mysqli_query($conn,"
SELECT status
FROM kontrol_pintu
WHERE id=1");
$row=mysqli_fetch_assoc($data);
echo $row['status'];

View File

@ -0,0 +1,26 @@
<?php
require_once __DIR__ . "/../config/db.php";
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($id > 0) {
$q = $conn->query("SELECT foto_path FROM log_akses WHERE id = {$id} LIMIT 1");
if ($q && $q->num_rows > 0) {
$data = $q->fetch_assoc();
if (!empty($data['foto_path'])) {
$relativePath = ltrim($data['foto_path'], '/');
$fullPath = dirname(__DIR__) . '/' . $relativePath;
if (file_exists($fullPath) && is_file($fullPath)) {
unlink($fullPath);
}
}
$conn->query("DELETE FROM log_akses WHERE id = {$id}");
}
}
header("Location: /smart-drop-point/public/log.php");
exit;

View File

@ -0,0 +1,356 @@
<?php
require_once __DIR__ . "/../config/db.php";
include __DIR__ . "/../partials/header.php";
include __DIR__ . "/../partials/sidebar.php";
// stats
$stats = [
"total_resi" => 0,
"resi_valid" => 0,
"resi_invalid" => 0,
"log_today" => 0,
"log_ok" => 0,
"log_fail" => 0
];
$r = $conn->query("SELECT COUNT(*) c, SUM(status='valid') v, SUM(status='invalid') i FROM resi");
if ($r && $row = $r->fetch_assoc()) {
$stats["total_resi"] = (int)($row["c"] ?? 0);
$stats["resi_valid"] = (int)($row["v"] ?? 0);
$stats["resi_invalid"] = (int)($row["i"] ?? 0);
}
$today = date("Y-m-d");
$r2 = $conn->query("
SELECT
COUNT(*) c,
SUM(status='berhasil') ok,
SUM(status='gagal') fail
FROM log_akses
WHERE DATE(created_at)='{$today}'
");
if ($r2 && $row2 = $r2->fetch_assoc()) {
$stats["log_today"] = (int)($row2["c"] ?? 0);
$stats["log_ok"] = (int)($row2["ok"] ?? 0);
$stats["log_fail"] = (int)($row2["fail"] ?? 0);
}
// latest logs
$latest = $conn->query("
SELECT
id,
nomor_resi,
status,
pesan,
created_at,
foto_path
FROM log_akses
ORDER BY created_at DESC
LIMIT 8
");
?>
<div class="row g-3">
<div class="col-12">
<div class="card-glass p-4">
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2">
<div>
<h3 class="mb-1">Dashboard</h3>
<div class="text-muted">
Ringkasan sistem monitoring paket & autentikasi resi.
</div>
</div>
<div class="d-flex gap-2">
<a class="btn btn-accent px-3 py-2 text-white"
href="/smart-drop-point/public/resi_add.php">
<i class="bi bi-plus-circle me-2"></i>
Tambah Resi
</a>
<a class="btn btn-danger px-3 py-2"
href="/smart-drop-point/public/manual_open.php"
onclick="return confirm('Yakin ingin membuka pintu secara manual?')">
🔓 Buka Pintu
</a>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card-glass p-3">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted">Total Resi Terdaftar</div>
<div class="fs-3 fw-bold">
<?= $stats["total_resi"] ?>
</div>
</div>
<div class="badge badge-soft p-2">
<i class="bi bi-upc-scan fs-4"></i>
</div>
</div>
<div class="mt-2 small text-muted">
Valid: <?= $stats["resi_valid"] ?>
Invalid: <?= $stats["resi_invalid"] ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card-glass p-3">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted">Total Scan Hari Ini</div>
<div class="fs-3 fw-bold">
<?= $stats["log_today"] ?>
</div>
</div>
<div class="badge badge-soft p-2">
<i class="bi bi-clock-history fs-4"></i>
</div>
</div>
<div class="mt-2 small text-muted">
Berhasil: <?= $stats["log_ok"] ?>
Gagal: <?= $stats["log_fail"] ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card-glass p-3">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted">Status Server</div>
<div class="fs-4 fw-bold">
<i class="bi bi-check-circle-fill me-2" style="color:#22c55e"></i>
Online
</div>
</div>
<div class="badge badge-soft p-2">
<i class="bi bi-hdd-network fs-4"></i>
</div>
</div>
<div class="mt-2 small text-muted">
Mode: Localhost (XAMPP)
</div>
</div>
</div>
<div class="col-12">
<div class="card-glass p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-semibold">
Log Terbaru
</div>
<a class="text-decoration-none"
href="/smart-drop-point/public/log.php">
Lihat semua
<i class="bi bi-arrow-right"></i>
</a>
</div>
<div class="table-responsive">
<table class="table table-dark table-hover align-middle mb-0">
<thead>
<tr>
<th>Waktu</th>
<th>Nomor Resi</th>
<th>Status</th>
<th>Pesan</th>
<th>Foto</th>
</tr>
</thead>
<tbody>
<?php if ($latest && $latest->num_rows > 0): ?>
<?php while ($x = $latest->fetch_assoc()): ?>
<tr>
<td class="text-muted">
<?= htmlspecialchars($x["created_at"]) ?>
</td>
<td class="fw-semibold">
<?= htmlspecialchars($x["nomor_resi"] ?? "-") ?>
</td>
<td>
<?php if ($x["status"] === "berhasil"): ?>
<span class="badge text-bg-success">
Berhasil
</span>
<?php else: ?>
<span class="badge text-bg-danger">
Gagal
</span>
<?php endif; ?>
</td>
<td class="text-muted">
<?= htmlspecialchars($x["pesan"] ?? "-") ?>
</td>
<td>
<?php if (!empty($x["foto_path"])): ?>
<a href="#"
data-foto-modal="1"
data-src="<?= htmlspecialchars($x["foto_path"]) ?>"
data-caption="<?= htmlspecialchars(($x["nomor_resi"] ?? "-") . " " . $x["created_at"]) ?>">
<img
src="<?= htmlspecialchars($x["foto_path"]) ?>"
alt="foto"
style="width:52px;height:52px;object-fit:cover;border-radius:10px;border:1px solid rgba(255,255,255,.2);cursor:pointer;"
>
</a>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="5" class="text-muted">
Belum ada log.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal fade" id="fotoModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content bg-dark text-light">
<div class="modal-header border-secondary">
<h5 class="modal-title">Bukti Foto</h5>
<button type="button"
class="btn-close btn-close-white"
data-bs-dismiss="modal">
</button>
</div>
<div class="modal-body text-center">
<img id="fotoModalImg"
src=""
alt="foto"
style="max-width:100%;height:auto;border-radius:12px;">
<div class="mt-2 text-muted small"
id="fotoModalCaption">
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("click", function (e) {
const a = e.target.closest("[data-foto-modal='1']");
if (!a) return;
e.preventDefault();
const src = a.getAttribute("data-src");
const caption = a.getAttribute("data-caption") || "";
document.getElementById("fotoModalImg").src = src;
document.getElementById("fotoModalCaption").textContent = caption;
const modal = new bootstrap.Modal(
document.getElementById("fotoModal")
);
modal.show();
});
document
.getElementById("fotoModal")
.addEventListener("hidden.bs.modal", function () {
document.getElementById("fotoModalImg").src = "";
document.getElementById("fotoModalCaption").textContent = "";
});
</script>
<?php include __DIR__ . "/../partials/footer.php"; ?>

View File

@ -0,0 +1,129 @@
<?php
require_once __DIR__ . "/../config/db.php";
include __DIR__ . "/../partials/header.php";
include __DIR__ . "/../partials/sidebar.php";
$status = $_GET["status"] ?? "";
$q = trim($_GET["q"] ?? "");
// Filter
$w = [];
if ($status === "berhasil" || $status === "gagal") {
$w[] = "status='" . $conn->real_escape_string($status) . "'";
}
if ($q !== "") {
$safe = $conn->real_escape_string($q);
$w[] = "nomor_resi LIKE '%{$safe}%'";
}
$where = count($w) ? "WHERE " . implode(" AND ", $w) : "";
// Ambil data log
$logs = $conn->query("SELECT * FROM log_akses {$where} ORDER BY created_at DESC LIMIT 300");
?>
<div class="card-glass p-4 mb-3">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
<div>
<h3 class="mb-1">Log Akses</h3>
<div class="text-muted">Riwayat autentikasi barcode (berhasil/gagal) + bukti foto.</div>
</div>
<a class="btn btn-outline-light" href="/smart-drop-point/public/log_add_mock.php">
<i class="bi bi-lightning-charge me-2"></i>Tambah Log Dummy
</a>
</div>
<form class="row g-2 mt-3" method="get">
<div class="col-md-5">
<input class="form-control" name="q"
value="<?= htmlspecialchars($q) ?>"
placeholder="Cari nomor resi...">
</div>
<div class="col-md-5">
<select class="form-select" name="status">
<option value="">Semua status</option>
<option value="berhasil" <?= $status === "berhasil" ? "selected" : "" ?>>berhasil</option>
<option value="gagal" <?= $status === "gagal" ? "selected" : "" ?>>gagal</option>
</select>
</div>
<div class="card-glass p-3">
<div class="table-responsive">
<table class="table table-dark table-hover align-middle mb-0">
<thead>
<tr>
<th>Waktu</th>
<th>Nomor Resi</th>
<th>Status</th>
<th>Pesan</th>
<th>Foto</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
<?php if ($logs && $logs->num_rows > 0): ?>
<?php while ($l = $logs->fetch_assoc()): ?>
<tr>
<td class="text-muted">
<?= htmlspecialchars($l["created_at"] ?? "-") ?>
</td>
<td class="fw-semibold">
<?= !empty($l["nomor_resi"]) ? htmlspecialchars($l["nomor_resi"]) : "-" ?>
</td>
<td>
<?php if (($l["status"] ?? "") === "berhasil"): ?>
<span class="badge text-bg-success">Berhasil</span>
<?php else: ?>
<span class="badge text-bg-danger">Gagal</span>
<?php endif; ?>
</td>
<td class="text-muted">
<?= htmlspecialchars($l["pesan"] ?? "-") ?>
</td>
<td>
<?php if (!empty($l["foto_path"])): ?>
<a target="_blank" href="<?= htmlspecialchars($l["foto_path"]) ?>">
<img
src="<?= htmlspecialchars($l["foto_path"]) ?>"
style="width:70px;height:70px;object-fit:cover;border-radius:10px;border:1px solid rgba(255,255,255,.2);"
alt="foto">
</a>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td class="text-center">
<a
href="/smart-drop-point/public/hapus_log.php?id=<?= (int)($l["id"] ?? 0) ?>"
class="btn btn-sm btn-outline-danger"
onclick="return confirm('Yakin mau hapus log ini?');"
title="Hapus log">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" class="text-muted text-center">
Belum ada log.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php include __DIR__ . "/../partials/footer.php"; ?>

View File

@ -0,0 +1,17 @@
<?php
require_once __DIR__ . "/../config/db.php";
// Generate resi random
$sampleResi = "JP" . rand(100000000, 999999999);
$status = (rand(0,1)===1) ? "berhasil" : "gagal";
$pesan = ($status==="berhasil") ? "Resi valid, akses dibuka." : "Resi tidak terdaftar.";
// Insert log
$stmt = $conn->prepare("INSERT INTO log_akses (nomor_resi, status, pesan) VALUES (?,?,?)");
$stmt->bind_param("sss", $sampleResi, $status, $pesan);
$stmt->execute();
$stmt->close();
// Redirect pakai cara aman
echo "<script>window.location.href='/smart-drop-point/public/log.php';</script>";
exit;

View File

@ -0,0 +1,10 @@
<?php
include "../config/db.php";
mysqli_query($conn,"
UPDATE kontrol_pintu
SET status='BUKA'
WHERE id=1");
echo "OK";

View File

@ -0,0 +1,10 @@
<?php
include "../config/db.php";
mysqli_query($conn,"
UPDATE kontrol_pintu
SET status='TUTUP'
WHERE id=1");
echo "RESET";

View File

@ -0,0 +1,113 @@
<?php
require_once __DIR__ . "/../config/db.php";
include __DIR__ . "/../partials/header.php";
include __DIR__ . "/../partials/sidebar.php";
$q = trim($_GET["q"] ?? "");
$where = "";
if ($q !== "") {
$safe = $conn->real_escape_string($q);
$where = "WHERE nomor_resi LIKE '%{$safe}%' OR nama_paket LIKE '%{$safe}%'";
}
$res = $conn->query("SELECT * FROM resi {$where} ORDER BY created_at DESC LIMIT 200");
?>
<div class="card-glass p-4 mb-3">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
<div>
<h3 class="mb-1">Data Resi</h3>
<div class="text-muted">Daftar resi yang boleh akses loker (valid/invalid).</div>
</div>
<div class="d-flex gap-2">
<a class="btn btn-accent text-white px-3" href="/smart-drop-point/public/resi_add.php">
<i class="bi bi-plus-circle me-2"></i>Tambah
</a>
<a class="btn btn-outline-light px-3" href="/smart-drop-point/public/log_add_mock.php">
<i class="bi bi-lightning-charge me-2"></i>Buat Log Dummy
</a>
</div>
</div>
<form class="row g-2 mt-3" method="get">
<div class="col-md-10">
<input
class="form-control"
name="q"
value="<?= htmlspecialchars($q) ?>"
placeholder="Cari nomor resi / nama paket..."
>
</div>
<div class="col-md-2 d-grid">
<button class="btn btn-outline-light" type="submit">
<i class="bi bi-search me-2"></i>Cari
</button>
</div>
</form>
</div>
<div class="card-glass p-3">
<div class="table-responsive">
<table class="table table-dark table-hover align-middle mb-0">
<thead>
<tr>
<th>Nomor Resi</th>
<th>Nama Paket</th>
<th>Status</th>
<th>Dibuat</th>
<th width="220">Aksi</th>
</tr>
</thead>
<tbody>
<?php if ($res && $res->num_rows > 0): ?>
<?php while ($r = $res->fetch_assoc()): ?>
<tr>
<td class="fw-semibold">
<?= htmlspecialchars($r["nomor_resi"] ?? "-") ?>
</td>
<td class="text-muted">
<?= htmlspecialchars($r["nama_paket"] ?? "-") ?>
</td>
<td>
<?php if (($r["status"] ?? "") === "valid"): ?>
<span class="badge text-bg-success">VALID</span>
<?php else: ?>
<span class="badge text-bg-secondary">INVALID</span>
<?php endif; ?>
</td>
<td class="text-muted">
<?= htmlspecialchars($r["created_at"] ?? "-") ?>
</td>
<td>
<div class="d-flex gap-2 flex-wrap">
<a class="btn btn-sm btn-outline-light" href="/smart-drop-point/public/resi_detail.php?id=<?= (int)$r["id"] ?>">
<i class="bi bi-eye me-1"></i>Detail
</a>
<a class="btn btn-sm btn-outline-warning" href="/smart-drop-point/public/resi_toggle.php?id=<?= (int)$r["id"] ?>">
<i class="bi bi-arrow-repeat me-1"></i>Toggle
</a>
</div>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="5" class="text-muted">Belum ada data resi.</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php include __DIR__ . "/../partials/footer.php"; ?>

View File

@ -0,0 +1,61 @@
<?php
require_once __DIR__ . "/../config/db.php";
include __DIR__ . "/../partials/header.php";
include __DIR__ . "/../partials/sidebar.php";
$err = ""; $ok = "";
if($_SERVER["REQUEST_METHOD"]==="POST"){
$nomor = trim($_POST["nomor_resi"] ?? "");
$nama = trim($_POST["nama_paket"] ?? "");
$status = $_POST["status"] ?? "valid";
if($nomor===""){
$err = "Nomor resi wajib diisi.";
} else {
$stmt = $conn->prepare("INSERT INTO resi (nomor_resi, nama_paket, status) VALUES (?,?,?)");
$stmt->bind_param("sss", $nomor, $nama, $status);
if($stmt->execute()){
$ok = "Resi berhasil ditambahkan.";
} else {
$err = "Gagal menambahkan resi. Mungkin resinya sudah ada.";
}
$stmt->close();
}
}
?>
<div class="card-glass p-4">
<h3 class="mb-1">Tambah Resi</h3>
<div class="text-muted mb-3">Masukkan resi yang dianggap valid untuk akses.</div>
<?php if($err): ?>
<div class="alert alert-danger"><?= htmlspecialchars($err) ?></div>
<?php endif; ?>
<?php if($ok): ?>
<div class="alert alert-success"><?= htmlspecialchars($ok) ?> <a href="/smart-drop-point/public/resi.php" class="alert-link">Lihat data</a></div>
<?php endif; ?>
<form method="post" class="row g-3">
<div class="col-md-6">
<label class="form-label">Nomor Resi</label>
<input class="form-control" name="nomor_resi" placeholder="contoh: JP123456789" required>
</div>
<div class="col-md-6">
<label class="form-label">Status</label>
<select class="form-select" name="status">
<option value="valid" selected>valid</option>
<option value="invalid">invalid</option>
</select>
</div>
<div class="col-12">
<label class="form-label">Nama Paket (opsional)</label>
<input class="form-control" name="nama_paket" placeholder="contoh: Paket Shopee / Buku / dll">
</div>
<div class="col-12 d-grid">
<button class="btn btn-accent text-white py-2"><i class="bi bi-check2-circle me-2"></i>Simpan</button>
</div>
</form>
</div>
<?php include __DIR__ . "/../partials/footer.php"; ?>

View File

@ -0,0 +1,64 @@
<?php
require_once __DIR__ . "/../config/db.php";
include __DIR__ . "/../partials/header.php";
include __DIR__ . "/../partials/sidebar.php";
$id = (int)($_GET["id"] ?? 0);
$stmt = $conn->prepare("SELECT * FROM resi WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$res = $stmt->get_result();
$data = $res->fetch_assoc();
?>
<div class="card-glass p-4 mb-3">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
<div>
<h3 class="mb-1">Detail Resi</h3>
<div class="text-muted">Informasi detail data resi paket.</div>
</div>
<a class="btn btn-outline-light" href="/smart-drop-point/public/resi.php">
<i class="bi bi-arrow-left me-2"></i>Kembali
</a>
</div>
</div>
<?php if ($data): ?>
<div class="card-glass p-4">
<table class="table table-dark table-bordered align-middle mb-0">
<tr>
<th width="220">Nomor Resi</th>
<td><?= htmlspecialchars($data["nomor_resi"] ?? "-") ?></td>
</tr>
<tr>
<th>Nama Paket</th>
<td><?= htmlspecialchars($data["nama_paket"] ?? "-") ?></td>
</tr>
<tr>
<th>Status</th>
<td>
<?php if (($data["status"] ?? "") === "valid"): ?>
<span class="badge text-bg-success">VALID</span>
<?php else: ?>
<span class="badge text-bg-secondary">INVALID</span>
<?php endif; ?>
</td>
</tr>
<tr>
<th>Dibuat</th>
<td><?= htmlspecialchars($data["created_at"] ?? "-") ?></td>
</tr>
</table>
</div>
<?php else: ?>
<div class="alert alert-danger">
Data resi tidak ditemukan.
</div>
<?php endif; ?>
<?php include __DIR__ . "/../partials/footer.php"; ?>

View File

@ -0,0 +1,18 @@
<?php
require_once __DIR__ . "/../config/db.php";
$id = (int)($_GET["id"] ?? 0);
// ambil status sekarang
$q = $conn->query("SELECT status FROM resi WHERE id = $id");
$data = $q->fetch_assoc();
if ($data) {
$newStatus = ($data["status"] === "valid") ? "invalid" : "valid";
$conn->query("UPDATE resi SET status='$newStatus' WHERE id=$id");
}
// balik lagi ke halaman resi
header("Location: resi.php");
exit;

View File

@ -0,0 +1,4 @@
<form action="upload_barcode.php" method="POST" enctype="multipart/form-data">
<input type="file" name="foto" required>
<button type="submit">Scan Barcode</button>
</form>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Test Upload Barcode</title>
</head>
<body>
<h2>Upload Foto Barcode</h2>
<form
action="api/upload_cam.php"
method="POST"
enctype="multipart/form-data"
>
<input
type="file"
name="foto"
accept="image/*"
required
>
<button type="submit">
Upload
</button>
</form>
</body>
</html>

View File

@ -0,0 +1,169 @@
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include "../config/db.php";
header("Content-Type: text/plain");
// =======================
// CEK FOTO
// =======================
if (!isset($_FILES['foto'])) {
echo "INVALID";
exit;
}
// =======================
// FOLDER UPLOAD
// =======================
$uploadDir = "uploads/";
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
// =======================
// SIMPAN FILE
// =======================
$filename = "cam_" . date("Ymd_His") . ".jpg";
$targetFile = $uploadDir . $filename;
if (!move_uploaded_file($_FILES['foto']['tmp_name'], $targetFile)) {
echo "UPLOAD GAGAL";
exit;
}
// =======================
// HASIL RESI
// =======================
$nomor_resi = "";
// =======================
// ZBAR BARCODE
// =======================
$zbar = shell_exec("\"C:\\ZBar\\bin\\zbarimg.exe\" --raw " . $targetFile);
$zbar = trim($zbar ?? "");
echo "ZBAR:\n";
echo $zbar;
echo "\n";
// =======================
// JIKA ZBAR BERHASIL
// =======================
if (!empty($zbar)) {
$nomor_resi = $zbar;
}
// =======================
// OCR FALLBACK
// =======================
if (empty($nomor_resi)) {
shell_exec("\"C:\\Program Files\\Tesseract-OCR\\tesseract.exe\" " . $targetFile . " uploads/hasil");
$ocrTxt = "uploads/hasil.txt";
if (file_exists($ocrTxt)) {
$ocr = file_get_contents($ocrTxt);
echo "\nOCR:\n";
echo $ocr;
echo "\n";
// regex khusus resi
preg_match('/JX[0-9A-Z]+/', $ocr, $match);
if (isset($match[0])) {
$nomor_resi = trim($match[0]);
}
}
}
// =======================
// DEBUG HASIL
// =======================
echo "\nHASIL FINAL:\n";
echo $nomor_resi;
echo "\n";
// =======================
// DEFAULT STATUS
// =======================
$status = "gagal";
$pesan = "Barcode / OCR tidak terbaca";
// =======================
// CEK DATABASE
// =======================
if (!empty($nomor_resi)) {
$stmt = $conn->prepare("SELECT * FROM resi WHERE nomor_resi=?");
$stmt->bind_param("s", $nomor_resi);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$status = "berhasil";
$pesan = "Resi valid, akses dibuka";
echo "\nVALID";
} else {
$status = "gagal";
$pesan = "Nomor resi tidak ditemukan";
echo "\nINVALID DATABASE";
}
} else {
echo "\nBARCODE / OCR GAGAL";
}
// =======================
// SIMPAN LOG
// =======================
$fotoWeb = "/smart-drop-point/public/" . $targetFile;
$stmtLog = $conn->prepare("
INSERT INTO log_akses
(
nomor_resi,
status,
pesan,
foto_path
)
VALUES
(
?, ?, ?, ?
)
");
$stmtLog->bind_param(
"ssss",
$nomor_resi,
$status,
$pesan,
$fotoWeb
);
$stmtLog->execute();
echo "\nLOG TERSIMPAN";
?>

View File

@ -0,0 +1,93 @@
<?php
require_once __DIR__ . '/../config/db.php';
date_default_timezone_set("Asia/Jakarta");
// 1) Folder simpan file (fisik)
$uploadDir = __DIR__ . '/../uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
if (!isset($_FILES['foto'])) {
die("Tidak ada file yang dikirim (name='foto').");
}
$f = $_FILES['foto'];
if ($f['error'] !== UPLOAD_ERR_OK) {
die("Upload error: " . $f['error']);
}
$ext = strtolower(pathinfo($f['name'], PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png'];
if (!in_array($ext, $allowed, true)) {
die("Format harus jpg/jpeg/png");
}
// 2) Simpan file
$filename = "scan_" . date("Ymd_His") . "_" . bin2hex(random_bytes(3)) . "." . $ext;
$targetPath = $uploadDir . $filename;
if (!move_uploaded_file($f['tmp_name'], $targetPath)) {
die("Gagal menyimpan file.");
}
// 3) Decode pakai ZBar
$zbar = '"C:\\Program Files (x86)\\ZBar\\bin\\zbarimg.exe"';
$cmd = $zbar . " " . escapeshellarg($targetPath) . " 2>&1";
$out = shell_exec($cmd);
if (!$out) {
$out = "";
}
// Ambil nomor resi: prioritas CODE-128, fallback QR-Code
$resi = null;
$lines = preg_split("/\r\n|\n|\r/", trim($out));
foreach ($lines as $line) {
if (preg_match('/^CODE-128:(.+)$/', trim($line), $m)) {
$resi = trim($m[1]);
break;
}
}
if ($resi === null) {
foreach ($lines as $line) {
if (preg_match('/^QR-Code:(.+)$/', trim($line), $m)) {
$resi = trim($m[1]);
break;
}
}
}
if ($resi === null || $resi === "") {
// kalau gak kebaca, tetap simpan log gagal biar ada bukti foto
$status = "gagal";
$pesan = "Barcode tidak terbaca.";
} else {
// 4) Cek resi valid di tabel resi (sesuaikan kalau nama tabel/kolom kamu beda)
$status = "gagal";
$pesan = "Resi tidak terdaftar.";
$stmt = $conn->prepare("SELECT 1 FROM resi WHERE nomor_resi = ? LIMIT 1");
$stmt->bind_param("s", $resi);
$stmt->execute();
$r = $stmt->get_result();
if ($r && $r->num_rows > 0) {
$status = "berhasil";
$pesan = "Resi valid, akses dibuka.";
}
}
// 5) Simpan ke tabel yang DIPAKAI log.php: log_akses
// log.php kamu pakai kolom: created_at, nomor_resi, status, pesan, foto_path
$fotoPathUrl = "/smart-drop-point/uploads/" . $filename;
$stmt2 = $conn->prepare("INSERT INTO log_akses (nomor_resi, status, pesan, foto_path, created_at) VALUES (?, ?, ?, ?, NOW())");
$stmt2->bind_param("ssss", $resi, $status, $pesan, $fotoPathUrl);
$stmt2->execute();
// 6) Balik ke halaman log (biar gak kepisah)
header("Location: /smart-drop-point/public/log.php");
exit;

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More