Upload project smart drop point
|
|
@ -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}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
||||
?>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
header("Location: public/");
|
||||
exit;
|
||||
?>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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">
|
||||
|
|
@ -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">
|
||||
|
|
@ -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() {
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
?>
|
||||
```
|
||||
|
|
@ -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'];
|
||||
|
|
@ -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;
|
||||
|
|
@ -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"; ?>
|
||||
|
|
@ -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"; ?>
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
include "../config/db.php";
|
||||
|
||||
mysqli_query($conn,"
|
||||
UPDATE kontrol_pintu
|
||||
SET status='BUKA'
|
||||
WHERE id=1");
|
||||
|
||||
echo "OK";
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
include "../config/db.php";
|
||||
|
||||
mysqli_query($conn,"
|
||||
UPDATE kontrol_pintu
|
||||
SET status='TUTUP'
|
||||
WHERE id=1");
|
||||
|
||||
echo "RESET";
|
||||
|
|
@ -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"; ?>
|
||||
|
|
@ -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"; ?>
|
||||
|
|
@ -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"; ?>
|
||||
|
|
@ -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;
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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";
|
||||
|
||||
?>
|
||||
|
|
@ -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;
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |