Fix: 500 error(DB logic) and Geolocation timeout issue
This commit is contained in:
Binary file not shown.
37
geoattendance/fix_geo_db.php
Normal file
37
geoattendance/fix_geo_db.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
echo "Starting Geo Attendance DB Fix...\n";
|
||||
|
||||
try {
|
||||
// Connect directly
|
||||
$dsn = "mysql:host=127.0.0.1;dbname=chandj;charset=utf8";
|
||||
$pdo = new PDO($dsn, 'root', 'root');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// 1. Check for ID 0 and move it if exists
|
||||
// We use a subquery to find a safe new ID
|
||||
echo "Checking for ID 0...\n";
|
||||
$stmt = $pdo->query("SELECT count(*) FROM geo_attendance WHERE id = 0");
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
echo " - Found row with ID 0. Moving it to a new ID...\n";
|
||||
// Calculate max id + 1
|
||||
$stmt = $pdo->query("SELECT MAX(id) FROM geo_attendance");
|
||||
$maxId = $stmt->fetchColumn();
|
||||
$newId = ($maxId > 0 ? $maxId : 0) + 1;
|
||||
|
||||
$pdo->exec("UPDATE geo_attendance SET id = $newId WHERE id = 0");
|
||||
echo " - ID 0 moved to $newId.\n";
|
||||
}
|
||||
|
||||
// 2. Apply AUTO_INCREMENT
|
||||
echo "Applying AUTO_INCREMENT to 'id' column...\n";
|
||||
$sql = "ALTER TABLE geo_attendance MODIFY id INT NOT NULL AUTO_INCREMENT";
|
||||
$pdo->exec($sql);
|
||||
echo " - Success! 'geo_attendance.id' is now AUTO_INCREMENT.\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
?>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SAM GeoWork - GPS 기반 출퇴근 시스템</title>
|
||||
<title>SAM GPS 기반 출퇴근 시스템</title>
|
||||
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
@@ -161,6 +161,9 @@
|
||||
const [distance, setDistance] = useState(null);
|
||||
const [activeTab, setActiveTab] = useState('home');
|
||||
|
||||
const [permissionStatus, setPermissionStatus] = useState('unknown');
|
||||
const [isSecure, setIsSecure] = useState(window.isSecureContext);
|
||||
|
||||
useEffect(() => {
|
||||
lucide.createIcons();
|
||||
}, [activeTab, records]);
|
||||
@@ -169,31 +172,79 @@
|
||||
useEffect(() => {
|
||||
loadRecords();
|
||||
loadOfficeConfig();
|
||||
checkPermission();
|
||||
}, []);
|
||||
|
||||
// Start watching location
|
||||
useEffect(() => {
|
||||
if ('geolocation' in navigator) {
|
||||
const watchId = navigator.geolocation.watchPosition(
|
||||
(position) => {
|
||||
const newLoc = {
|
||||
latitude: position.coords.latitude,
|
||||
longitude: position.coords.longitude,
|
||||
accuracy: position.coords.accuracy
|
||||
};
|
||||
setCurrentLocation(newLoc);
|
||||
setErrorMsg(null);
|
||||
},
|
||||
(err) => {
|
||||
console.error(err);
|
||||
setErrorMsg("Unable to retrieve location. Please enable GPS.");
|
||||
},
|
||||
{ enableHighAccuracy: true, maximumAge: 10000, timeout: 5000 }
|
||||
);
|
||||
return () => navigator.geolocation.clearWatch(watchId);
|
||||
} else {
|
||||
setErrorMsg("Geolocation is not supported by your browser.");
|
||||
const checkPermission = async () => {
|
||||
if (navigator.permissions && navigator.permissions.query) {
|
||||
try {
|
||||
const result = await navigator.permissions.query({ name: 'geolocation' });
|
||||
setPermissionStatus(result.state);
|
||||
result.onchange = () => {
|
||||
setPermissionStatus(result.state);
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Permission query failed", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start watching location with fallback logic
|
||||
useEffect(() => {
|
||||
let watchId = null;
|
||||
|
||||
const startWatch = (highAccuracy = true) => {
|
||||
if (watchId) navigator.geolocation.clearWatch(watchId);
|
||||
|
||||
if ('geolocation' in navigator) {
|
||||
watchId = navigator.geolocation.watchPosition(
|
||||
(position) => {
|
||||
const newLoc = {
|
||||
latitude: position.coords.latitude,
|
||||
longitude: position.coords.longitude,
|
||||
accuracy: position.coords.accuracy
|
||||
};
|
||||
setCurrentLocation(newLoc);
|
||||
setErrorMsg(null);
|
||||
},
|
||||
(err) => {
|
||||
console.error(err);
|
||||
|
||||
// On Timeout (code 3) and currently using High Accuracy, try fallback
|
||||
if (err.code === 3 && highAccuracy) {
|
||||
console.warn("High accuracy timed out. Falling back to low accuracy.");
|
||||
startWatch(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = "위치를 가져올 수 없습니다.";
|
||||
switch(err.code) {
|
||||
case 1: msg = "위치 정보 권한이 거부되었습니다. 브라우저 설정에서 권한을 허용해주세요."; break;
|
||||
case 2: msg = "위치 정보를 사용할 수 없습니다. GPS 신호를 확인해주세요."; break;
|
||||
case 3: msg = "위치 정보 요청 시간이 초과되었습니다. (Low Accuracy 시도 실패)"; break;
|
||||
default: msg = "알 수 없는 오류가 발생했습니다. (" + err.message + ")"; break;
|
||||
}
|
||||
if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') {
|
||||
msg += " (주의: 보안 연결(HTTPS)이 아니면 위치 정보가 차단될 수 있습니다)";
|
||||
}
|
||||
setErrorMsg(msg);
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: highAccuracy,
|
||||
maximumAge: 10000,
|
||||
timeout: 15000 // 15 seconds timeout
|
||||
}
|
||||
);
|
||||
} else {
|
||||
setErrorMsg("Geolocation is not supported by your browser.");
|
||||
}
|
||||
};
|
||||
|
||||
startWatch(true); // Start with High Accuracy
|
||||
|
||||
return () => {
|
||||
if (watchId) navigator.geolocation.clearWatch(watchId);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Recalculate distance when location or office changes
|
||||
@@ -437,8 +488,25 @@
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
|
||||
<h3 className="font-medium text-gray-800 mb-2">디버그 정보</h3>
|
||||
<div className="text-xs font-mono text-gray-500 space-y-1">
|
||||
<h3 className="font-medium text-gray-800 mb-2">시스템 상태 확인</h3>
|
||||
<div className="text-xs font-mono text-gray-500 space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span>GPS 권한:</span>
|
||||
<span className={`font-bold ${permissionStatus === 'granted' ? 'text-green-600' : 'text-red-500'}`}>
|
||||
{permissionStatus === 'granted' ? '허용됨' : permissionStatus === 'prompt' ? '대기중(물어봄)' : '거부됨'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span>보안 연결(HTTPS):</span>
|
||||
<span className={`font-bold ${isSecure ? 'text-green-600' : 'text-red-500'}`}>
|
||||
{isSecure ? '안전함' : '불안전(HTTP)'}
|
||||
</span>
|
||||
</div>
|
||||
{!isSecure && (
|
||||
<p className="text-red-500 bg-red-50 p-2 rounded">
|
||||
주의: HTTPS가 아니면 최신 브라우저에서 GPS가 차단됩니다.
|
||||
</p>
|
||||
)}
|
||||
<p>거리: {distance ? distance.toFixed(1) : '알 수 없음'} 미터</p>
|
||||
<p>반경 제한: {office.allowedRadiusMeters} 미터</p>
|
||||
<p>GPS 정확도: {currentLocation?.accuracy ? currentLocation.accuracy.toFixed(1) + 'm' : '알 수 없음'}</p>
|
||||
|
||||
@@ -41,13 +41,14 @@ function checkNull($strtmp) {
|
||||
|
||||
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
|
||||
$mode = isset($_REQUEST["mode"]) ? $_REQUEST["mode"] : '';
|
||||
$sort_order = isset($_REQUEST['sort_order']) ? $_REQUEST['sort_order'] : 'DESC';
|
||||
|
||||
$tablename = 'holiday';
|
||||
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
|
||||
$pdo = db_connect();
|
||||
|
||||
$order = " ORDER BY registedate DESC, num desc ";
|
||||
$order = " ORDER BY startdate " . ($sort_order === 'ASC' ? 'ASC' : 'DESC') . ", num desc ";
|
||||
|
||||
if (checkNull($search)) {
|
||||
$sql = "SELECT * FROM ".$DB.".".$tablename."
|
||||
@@ -65,7 +66,8 @@ try {
|
||||
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
|
||||
<input type="hidden" id="num" name="num">
|
||||
<input type="hidden" id="tablename" name="tablename" value="<?=$tablename?>">
|
||||
<input type="hidden" id="header" name="header" value="<?=$header?>">
|
||||
<input type="hidden" id="header" name="header" value="<?=$header?>">
|
||||
<input type="hidden" id="sort_order" name="sort_order" value="<?=$sort_order?>">
|
||||
|
||||
|
||||
<div class="container">
|
||||
@@ -112,7 +114,9 @@ try {
|
||||
<table class="table table-hover" id="myTable">
|
||||
<thead class="table-info">
|
||||
<th class="text-center " >번호</th>
|
||||
<th class="text-center " >휴일시작</th>
|
||||
<th class="text-center sortable-header" id="sortStartDate" style="cursor: pointer;" >휴일시작
|
||||
<i class="bi bi-arrow-<?=$sort_order === 'ASC' ? 'up' : 'down'?>"></i>
|
||||
</th>
|
||||
<th class="text-center " >휴일종료</th>
|
||||
<th class="text-center " >기간체크</th>
|
||||
<th class="text-center " >내용</th>
|
||||
@@ -179,6 +183,15 @@ $(document).ready(function() {
|
||||
$("#searchBtn").on("click", function() {
|
||||
$("#board_form").submit();
|
||||
});
|
||||
|
||||
// 휴일시작 헤더 클릭 시 정렬 토글
|
||||
$("#sortStartDate").on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
var currentOrder = $("#sort_order").val();
|
||||
var newOrder = (currentOrder === 'DESC') ? 'ASC' : 'DESC';
|
||||
$("#sort_order").val(newOrder);
|
||||
$("#board_form").submit();
|
||||
});
|
||||
});
|
||||
|
||||
function loadForm(mode, num = null) {
|
||||
|
||||
BIN
img/uploads/2019_11_15_15_31_48_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_31_48_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
img/uploads/2019_11_15_15_38_20_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_38_20_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
img/uploads/2019_11_15_15_42_26_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_42_26_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
img/uploads/2019_11_15_15_43_33_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_43_33_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
img/uploads/2019_11_15_15_48_30_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_48_30_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
img/uploads/2019_11_15_15_50_51_.JPG
Normal file
BIN
img/uploads/2019_11_15_15_50_51_.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
12
output/debug_schema.php
Normal file
12
output/debug_schema.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
$_SERVER['DOCUMENT_ROOT'] = 'c:/Users/light/sam/5130';
|
||||
require_once 'c:/Users/light/sam/5130/lib/mydb.php';
|
||||
try {
|
||||
$pdo = db_connect();
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM output LIKE 'num'");
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
print_r($row);
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
?>
|
||||
54
output/fix_db_autoincrement.php
Normal file
54
output/fix_db_autoincrement.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
$_SERVER['DOCUMENT_ROOT'] = 'c:/Users/light/sam/5130';
|
||||
require_once 'c:/Users/light/sam/5130/lib/mydb.php';
|
||||
|
||||
echo "Starting DB Schema Fix...\n";
|
||||
|
||||
try {
|
||||
// Connect directly to avoid .env overwriting with 'mysql' host
|
||||
$dsn = "mysql:host=127.0.0.1;dbname=chandj;charset=utf8";
|
||||
$pdo = new PDO($dsn, 'root', 'root');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$DB = 'chandj';
|
||||
|
||||
// 1. Fix output table
|
||||
echo "Fixing 'output' table...\n";
|
||||
// Check if auto_increment exists or just try to apply it
|
||||
// Usually 'MODIFY num INT AUTO_INCREMENT' works. Assuming 'num' is int.
|
||||
// We also need to make sure we don't break existing keys.
|
||||
// Safest is "MODIFY num INT NOT NULL AUTO_INCREMENT"
|
||||
$sql = "ALTER TABLE {$DB}.output MODIFY num INT NOT NULL AUTO_INCREMENT";
|
||||
$pdo->exec($sql);
|
||||
echo " - 'output.num' set to AUTO_INCREMENT successfully.\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - Error fixing 'output': " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
// 2. Fix geo_attendance table
|
||||
// First, find the primary key column name
|
||||
echo "Fixing 'geo_attendance' table...\n";
|
||||
$stmt = $pdo->query("SHOW KEYS FROM {$DB}.geo_attendance WHERE Key_name = 'PRIMARY'");
|
||||
$pk = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($pk) {
|
||||
$pkColumn = $pk['Column_name'];
|
||||
echo " - Found Primary Key column: $pkColumn\n";
|
||||
|
||||
$sql = "ALTER TABLE {$DB}.geo_attendance MODIFY $pkColumn INT NOT NULL AUTO_INCREMENT";
|
||||
$pdo->exec($sql);
|
||||
echo " - 'geo_attendance.$pkColumn' set to AUTO_INCREMENT successfully.\n";
|
||||
} else {
|
||||
echo " - Could not find Primary Key for geo_attendance.\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo " - Error fixing 'geo_attendance': " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "Done.\n";
|
||||
?>
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
// ini_set('display_errors', 1);
|
||||
// ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
|
||||
header("Content-Type: application/json");
|
||||
|
||||
|
||||
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
|
||||
$num = isset($_REQUEST['num']) ? $_REQUEST['num'] : '';
|
||||
$tablename = isset($_REQUEST['tablename']) ? $_REQUEST['tablename'] : '';
|
||||
@@ -157,9 +157,12 @@ $searchtag = rtrim($searchtag, ' ');
|
||||
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
|
||||
$pdo = db_connect();
|
||||
$DB = $_ENV['DB_NAME'] ?? 'chandj';
|
||||
|
||||
|
||||
try {
|
||||
if ($mode == "insert" || $mode == "copy") {
|
||||
|
||||
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " ";
|
||||
$pdo->beginTransaction();
|
||||
|
||||
@@ -178,6 +181,7 @@ try {
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$stmh = $pdo->prepare($sql);
|
||||
|
||||
$stmh->execute([
|
||||
$outdate, $indate, $orderman, $outworkplace, $outputplace,
|
||||
$receiver, $phone, $comment, $con_num, $root,
|
||||
@@ -291,7 +295,8 @@ try {
|
||||
$pdo->commit();
|
||||
} catch (Exception $ex) {
|
||||
$pdo->rollBack();
|
||||
print "오류: ".$Exception->getMessage();
|
||||
// print "오류: ".$Exception->getMessage();
|
||||
throw new Exception($ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +322,8 @@ try {
|
||||
$pdo->commit();
|
||||
} catch (PDOException $Exception) {
|
||||
$pdo->rollBack();
|
||||
print "오류: ".$Exception->getMessage();
|
||||
// print "오류: ".$Exception->getMessage();
|
||||
throw new Exception($Exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
250717-02
|
||||
251214-03
|
||||
@@ -31,6 +31,9 @@ $first_approval_id = $_SESSION["first_approval_id"] ?? '';
|
||||
$first_approval_name = $_SESSION["first_approval_name"] ?? '';
|
||||
|
||||
// APP_URL 기반 동적 URL 설정
|
||||
$root_dir = rtrim($_ENV['APP_URL'] ?? 'https://5130.co.kr', '/');
|
||||
// APP_URL 기반 동적 URL 설정
|
||||
// $root_dir = rtrim($_ENV['APP_URL'] ?? 'https://5130.co.kr', '/');
|
||||
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? "https://" : "http://";
|
||||
$root_dir = $protocol . $_SERVER['HTTP_HOST'];
|
||||
$WebSite = $root_dir . '/';
|
||||
?>
|
||||
Reference in New Issue
Block a user