티스토리 뷰
반응형
아래의 형태의 셔터의 가이드레일 이미지를 관리하는 로직을 개발중이다.
단순 파일선택을 통해 불러오는 구조가 아닌, 윈도우 화면 캡쳐기능을 추가한 편리한 이미지 저장로직을 만들고자 한다.
chatGPT 4.0 기준으로 다시금 코드를 재생산 해본다.
아래의 코드는 guiderail을 json, 형태로 조건값과 이미지를 저장하는 코드이다.
기존의 이미지를 단순하게 파일찾기 기능으로 추가하던 코드를 drop 및 윈도우 화면캡쳐 기능을 추가하는 코드를 삽입했다.
기존의 단순 이미지를 불러와서 저장하는 방식에서 좀더 UI를 개선하는 코드를 넣었다.
이제 기존의 이미지를 저장하는 로직에서 drop Area 및 화면 캡쳐 기능이 작동하게 코드를 일부 수정해줘.
기존의 이미지처리부분의 로직을 수정해주길 바랍니다.
<?php
// guideraillist.php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location: /login/login_form.php");
exit;
}
$title_message = '가이드레일 이미지 관리';
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/guiderail/guiderail.json';
// JSON 파일이 존재하면 읽어오고, 없으면 빈 배열 생성
$guiderailData = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$guiderailData = json_decode($jsonContent, true);
if (!is_array($guiderailData)) {
$guiderailData = [];
}
}
// POST 요청 처리: 추가, 수정, 삭제
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = isset($_POST['action']) ? $_POST['action'] : '';
$index = isset($_POST['index']) ? intval($_POST['index']) : -1;
$firstitem = isset($_POST['firstitem']) ? trim($_POST['firstitem']) : '';
$model_name = isset($_POST['model_name']) ? trim($_POST['model_name']) : '';
$check_type = isset($_POST['check_type']) ? trim($_POST['check_type']) : '';
// 이미지 파일 업로드 처리
$imagePath = '';
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/guiderail/images/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$originalName = $_FILES['image']['name'];
$tmpName = $_FILES['image']['tmp_name'];
// 파일명과 확장자 분리 (pathinfo 사용)
$pathInfo = pathinfo($originalName);
$fileName = $pathInfo['filename']; // 확장자 제외한 파일명
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
// 파일명에 한글, 특수문자 제거: 영문, 숫자, _ , - 만 허용
$fileNameSanitized = preg_replace('/[^A-Za-z0-9_\-]/', '_', $fileName);
// 새 파일명 생성: 현재 날짜와 시간 + "_" + 정제된 파일명 + .확장자
$newFileName = date("Y_m_d_H_i_s") . "_" . $fileNameSanitized;
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$targetFile = $uploadDir . $newFileName;
if (!move_uploaded_file($tmpName, $targetFile)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
// 업로드 성공 시 상대 경로 저장
$imagePath = '/guiderail/images/' . $newFileName;
}
// 만약 새 이미지가 업로드되지 않았으면 기존 이미지(hidden input)을 사용
if (empty($imagePath) && isset($_POST['existing_image'])) {
$imagePath = trim($_POST['existing_image']);
}
if ($action === 'insert' && !empty($model_name)) {
// 신규 추가
$guiderailData[] = array(
"firstitem" => $firstitem,
"model_name" => $model_name,
"check_type" => $check_type,
"image" => $imagePath
);
} elseif ($action === 'update' && !empty($model_name) && $index >= 0 && $index < count($guiderailData)) {
// 수정: 해당 인덱스의 데이터를 업데이트
$guiderailData[$index]["firstitem"] = $firstitem;
$guiderailData[$index]["model_name"] = $model_name;
$guiderailData[$index]["check_type"] = $check_type;
if (!empty($imagePath)) {
$guiderailData[$index]["image"] = $imagePath;
}
} elseif ($action === 'delete' && $index >= 0 && $index < count($guiderailData)) {
// 삭제: 해당 요소 제거
array_splice($guiderailData, $index, 1);
}
// JSON 파일에 저장
file_put_contents($jsonFile, json_encode($guiderailData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
?>
</head>
<body>
<div class="container mt-3">
<div class="card">
<div class="card-header d-flex justify-content-center align-items-center text-center">
<h3><?= $title_message ?></h3>
<button type="button" class="btn btn-dark btn-sm mx-5" onclick="window.close();">
<i class="bi bi-x-square"></i> 닫기
</button>
</div>
<div class="card-body">
<!-- 신규/수정 폼 -->
<form id="guiderailForm" method="post" action="guideraillist.php" enctype="multipart/form-data" class="row g-3">
<input type="hidden" name="action" id="action" value="insert">
<input type="hidden" name="index" id="index" value="-1">
<input type="hidden" name="existing_image" id="existing_image" value="">
<div class="col-auto">
<!-- 대분류 선택 -->
<select id="firstitem" name="firstitem" class="form-select mx-1 d-block w-auto" style="font-size: 0.8rem; height: 32px;">
<option value="">(대분류)</option>
<option value="스크린" <?= ($firstitem == '스크린') ? 'selected' : '' ?>>스크린</option>
<option value="철재" <?= ($firstitem == '철재') ? 'selected' : '' ?>>철재</option>
</select>
</div>
<div class="col-auto">
<!-- 제품모델(KSS01 등) 선택 -->
<?php
// JSON 파일 경로 (예: /models/models.json)
$jsonFile = $_SERVER['DOCUMENT_ROOT'].'/models/models.json';
$modelsList = [];
if(file_exists($jsonFile)){
$jsonContent = file_get_contents($jsonFile);
$modelsList = json_decode($jsonContent, true);
if(!is_array($modelsList)) {
$modelsList = [];
}
}
// 기존 데이터가 있으면 기본 선택할 값
$selectedModel = isset($row['model_name']) ? $row['model_name'] : '';
// 대분류 선택값
$selectedMajor = isset($row['major_category']) ? $row['major_category'] : '';
?>
<select id="model_name" name="model_name" class="form-select mx-1 d-block w-auto" style="font-size: 0.8rem; height: 32px;">
<option value="">(모델 선택)</option>
<?php
// 초기 옵션: 대분류가 선택되어 있으면 해당 모델만 표시
foreach($modelsList as $model):
if($selectedMajor === '' || $model['slatitem'] === $selectedMajor):
?>
<option value="<?= htmlspecialchars($model['model_name'], ENT_QUOTES, 'UTF-8') ?>" <?= ($model_name === $model['model_name']) ? 'selected' : '' ?>>
<?= htmlspecialchars($model['model_name'], ENT_QUOTES, 'UTF-8') ?>
</option>
<?php
endif;
endforeach;
?>
</select>
</div>
<div class="col-auto">
<!-- 체크타입 선택 -->
<select name="check_type" id="check_type" class="form-select mx-1 d-block w-auto" style="font-size: 0.8rem; height: 32px;">
<option value="">(유형)</option>
<option value="벽면형" <?= ($check_type == '벽면형') ? 'selected' : '' ?>>벽면형</option>
<option value="측면형" <?= ($check_type == '측면형') ? 'selected' : '' ?>>측면형</option>
</select>
</div>
<div class="col-auto">
<!-- 이미지 파일 선택 -->
<input type="file" name="image" id="image" class="form-control">
<div class="card">
<div class="card-body">
<!-- 기존 이미지 표시 영역 -->
<div class="card mb-3">
<div class="card-body">
<div id="previewContainer" class="text-center mb-3"
ondragover="event.preventDefault();"
ondrop="event.preventDefault();">
<?php if (!empty($imgdata)): ?>
<img src="<?= $upload_dir . $imgdata ?>" alt="Image" id="currentImage" class="img-fluid">
<?php else: ?>
아직 등록된 이미지가 없습니다.
<?php endif; ?>
</div>
</div>
</div>
<?php if($mode!=='view') : ?>
<!-- 파일 선택 -->
<input type="file" id="upfile" name="upfile[]" multiple style="display:none;">
<button class="btn btn-dark btn-sm me-4" type="button" onclick="document.getElementById('upfile').click();">
<i class="bi bi-image"></i>
</button>
<div class="d-flex justify-content-center">
<!-- 드롭 영역 -->
<div id="dropArea" style="border: 1px dashed #ccc; padding: 5px; width:100%; height:80px; text-align: center;">
여기로 사진을 drop 하세요!
</div>
</div>
<!-- 파일 목록 표시 -->
<div class="d-flex mt-2 justify-content-center">
<div id="displayfile"></div>
</div>
<?php endif; ?>
</div>
<!-- JavaScript for handling drag and drop -->
<script>
document.getElementById('dropArea').addEventListener('dragover', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#000'; // 드래그 시 테두리 색상 변경
});
document.getElementById('dropArea').addEventListener('dragleave', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#ccc'; // 드래그 영역 벗어날 때 테두리 색상 복원
});
document.getElementById('dropArea').addEventListener('drop', function(event) {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
if (files.length > 0) {
handleFiles(files);
}
});
document.getElementById('upfile').addEventListener('change', function(event) {
const files = event.target.files;
if (files.length > 0) {
handleFiles(files);
}
});
function handleFiles(files) {
const file = files[0]; // 첫 번째 파일만 처리
const reader = new FileReader();
reader.onload = function(event) {
const img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
const previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = ''; // 기존 이미지 제거
previewContainer.appendChild(img);
// 실제 파일 데이터를 <input type="file">에 설정
const fileInput = document.getElementById('upfile');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(file);
}
</script>
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary" id="submitBtn">등록</button>
</div>
</form>
<hr>
<!-- 저장된 가이드레일 이미지 목록 테이블 -->
<div class="table-responsive">
<table class="table table-bordered">
<thead class="table-secondary">
<tr>
<th>순번</th>
<th>대분류</th>
<th>모델명</th>
<th>유형</th>
<th>이미지</th>
<th>수정/삭제</th>
</tr>
</thead>
<tbody>
<?php if (!empty($guiderailData)): ?>
<?php foreach ($guiderailData as $i => $item): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= htmlspecialchars($item["firstitem"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($item["model_name"], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($item["check_type"], ENT_QUOTES, 'UTF-8') ?></td>
<td>
<?php if (!empty($item["image"])): ?>
<img src="<?= htmlspecialchars($item["image"], ENT_QUOTES, 'UTF-8') ?>" alt="이미지" style="max-width:100px;">
<?php else: ?>
없음
<?php endif; ?>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-primary editBtn" data-index="<?= $i ?>">수정</button>
<button type="button" class="btn btn-sm btn-outline-danger deleteBtn" data-index="<?= $i ?>">삭제</button>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="6">등록된 가이드레일 이미지 정보가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div><!-- table-responsive -->
</div><!-- card-body -->
</div><!-- card -->
</div><!-- container -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
});
$(document).ready(function(){
// 수정 버튼 클릭 시: 해당 행의 데이터를 폼에 채워 수정 모드로 전환
$('.editBtn').on('click', function(){
var index = $(this).data('index');
var row = $(this).closest('tr');
var firstitem = row.find('td:eq(1)').text().trim();
var modelName = row.find('td:eq(2)').text().trim();
var checkType = row.find('td:eq(3)').text().trim();
var imageSrc = row.find('td:eq(4) img').attr('src') || '';
$('#firstitem').val(firstitem);
$('#model_name').val(modelName);
$('#check_type').val(checkType);
$('#existing_image').val(imageSrc);
$('#index').val(index);
$('#action').val('update');
$('#submitBtn').text('수정');
});
// 삭제 버튼 클릭 시: 확인 후 폼 제출하여 삭제 처리
$('.deleteBtn').on('click', function(){
var index = $(this).data('index');
if(confirm("정말 삭제하시겠습니까?")){
$('#index').val(index);
$('#action').val('delete');
$('#guiderailForm').submit();
}
});
});
</script>
<script>
// PHP에서 전달받은 모델 리스트를 JavaScript 변수에 저장
var modelsList = <?php echo json_encode($modelsList); ?>;
$(document).ready(function(){
$('#firstitem').on('change', function(){
var selectedMajor = $(this).val();
var $modelSelect = $('#model_name');
// 기존 옵션 초기화
$modelSelect.empty();
// 기본 옵션 추가
$modelSelect.append('<option value="">(모델 선택)</option>');
// 모델 리스트를 순회하며 대분류(selectedMajor)와 일치하는 경우 옵션 추가
$.each(modelsList, function(index, model){
if(selectedMajor === '' || model.slatitem === selectedMajor){
var option = $('<option>')
.val(model.model_name)
.text(model.model_name);
$modelSelect.append(option);
}
});
});
});
// 윈도우키 + Shift + S를 사용하여 화면 캡처한 이미지를 바로 붙여넣기하면, 클립보드에 이미지가 저장
document.addEventListener('paste', function (event) {
let items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (let index in items) {
let item = items[index];
if (item.kind === 'file' && item.type.startsWith('image/')) {
let blob = item.getAsFile();
let reader = new FileReader();
reader.onload = function (event) {
// 이미지 미리보기 영역 업데이트
let previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = '';
let img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
previewContainer.appendChild(img);
// 파일을 input[type=file] 요소에 추가
let fileInput = document.getElementById('upfile');
let dataTransfer = new DataTransfer();
dataTransfer.items.add(blob);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(blob);
}
}
});
</script>
</body>
</html>
위의 프롬프트로 실제 인공지능을 이용해서 결과치를 받아본다.
다음은 기존의 이미지 업로드 처리 로직을 수정하여,
- 먼저 drop 영역(파일 input name="upfile[]")에서 업로드된 파일을 우선적으로 처리하고,
- 그 다음 기존의 파일 input(name="image")의 파일을 처리하며,
- 둘 다 없으면 기존 hidden input("existing_image")의 값을 사용하는 코드입니다.
// 이미지 파일 업로드 처리 (drop 영역 및 일반 파일 input 모두 지원)
$imagePath = '';
// 1. drop 영역에서 업로드된 파일 처리 (파일 input name="upfile[]"가 존재하고, 첫 번째 파일의 크기가 0보다 큰 경우)
if (isset($_FILES['upfile']) && isset($_FILES['upfile']['size'][0]) && $_FILES['upfile']['size'][0] > 0) {
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/guiderail/images/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$originalName = $_FILES['upfile']['name'][0];
$tmpName = $_FILES['upfile']['tmp_name'][0];
// 파일명과 확장자 분리 (pathinfo 사용)
$pathInfo = pathinfo($originalName);
$fileName = $pathInfo['filename']; // 확장자 제외한 파일명
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
// 파일명에 한글, 특수문자 제거: 영문, 숫자, _ , - 만 허용
$fileNameSanitized = preg_replace('/[^A-Za-z0-9_\-]/', '_', $fileName);
// 새 파일명 생성: 현재 날짜와 시간 + "_" + 정제된 파일명 + .확장자
$newFileName = date("Y_m_d_H_i_s") . "_" . $fileNameSanitized;
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$targetFile = $uploadDir . $newFileName;
if (!move_uploaded_file($tmpName, $targetFile)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
// 업로드 성공 시 상대 경로 저장
$imagePath = '/guiderail/images/' . $newFileName;
// 2. 일반 파일 input (name="image")에서 업로드된 파일 처리
} elseif (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/guiderail/images/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$originalName = $_FILES['image']['name'];
$tmpName = $_FILES['image']['tmp_name'];
$pathInfo = pathinfo($originalName);
$fileName = $pathInfo['filename'];
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
$fileNameSanitized = preg_replace('/[^A-Za-z0-9_\-]/', '_', $fileName);
$newFileName = date("Y_m_d_H_i_s") . "_" . $fileNameSanitized;
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$targetFile = $uploadDir . $newFileName;
if (!move_uploaded_file($tmpName, $targetFile)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
$imagePath = '/guiderail/images/' . $newFileName;
}
// 3. 만약 새 이미지가 업로드되지 않았으면 기존 이미지(hidden input)를 사용
if (empty($imagePath) && isset($_POST['existing_image'])) {
$imagePath = trim($_POST['existing_image']);
}
클라이언트 측 (HTML + JavaScript)
이미지 업로드와 관련된 UI에는 다음과 같이 드래그 앤 드롭 영역과 화면 캡쳐(클립보드 붙여넣기) 기능을 포함합니다.
<!-- 이미지 파일 선택 및 드롭 영역 -->
<div class="col-auto">
<!-- 이미지 파일 선택 (숨김 처리, drop 영역에서 사용) -->
<input type="file" id="upfile" name="upfile[]" multiple style="display:none;">
<button class="btn btn-dark btn-sm me-4" type="button" onclick="document.getElementById('upfile').click();">
<i class="bi bi-image"></i>
</button>
<div class="d-flex justify-content-center">
<!-- 드롭 영역 -->
<div id="dropArea" style="border: 1px dashed #ccc; padding: 5px; width:100%; height:80px; text-align: center;">
여기로 사진을 drop 하세요!
</div>
</div>
<!-- 파일 목록 및 미리보기 영역 -->
<div class="d-flex mt-2 justify-content-center">
<div id="previewContainer">
<?php if (!empty($imgdata)): ?>
<img src="<?= htmlspecialchars($upload_dir . $imgdata, ENT_QUOTES, 'UTF-8') ?>" alt="Image" id="currentImage" class="img-fluid">
<?php else: ?>
아직 등록된 이미지가 없습니다.
<?php endif; ?>
</div>
</div>
</div>
<!-- JavaScript for Drag & Drop, 파일 선택, 그리고 클립보드 붙여넣기 -->
<script>
document.getElementById('dropArea').addEventListener('dragover', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#000';
});
document.getElementById('dropArea').addEventListener('dragleave', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#ccc';
});
document.getElementById('dropArea').addEventListener('drop', function(event) {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
if (files.length > 0) {
handleFiles(files);
}
});
document.getElementById('upfile').addEventListener('change', function(event) {
const files = event.target.files;
if (files.length > 0) {
handleFiles(files);
}
});
// 클립보드 붙여넣기 (윈도우키+Shift+S 등)
document.addEventListener('paste', function(event) {
let items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (let index in items) {
let item = items[index];
if (item.kind === 'file' && item.type.startsWith('image/')) {
let blob = item.getAsFile();
let reader = new FileReader();
reader.onload = function(event) {
const previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = '';
let img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
previewContainer.appendChild(img);
// 파일을 upfile input에 추가
const fileInput = document.getElementById('upfile');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(blob);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(blob);
}
}
});
function handleFiles(files) {
const file = files[0]; // 첫 번째 파일만 처리 (필요에 따라 확장 가능)
const reader = new FileReader();
reader.onload = function(event) {
const previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = '';
let img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
previewContainer.appendChild(img);
// 파일을 upfile input에 설정
const fileInput = document.getElementById('upfile');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(file);
}
</script>
요약
- 서버 측에서는 먼저 $_FILES['upfile'] (드롭 영역/붙여넣기 처리된 파일)을 우선적으로 처리하고,
그 후 $_FILES['image']를 확인하며, 둘 다 없으면 기존 이미지 값을 사용하도록 수정하였습니다. - 클라이언트 측에서는 드래그 앤 드롭 영역, 파일 선택 버튼, 그리고 클립보드 붙여넣기 이벤트를 처리하여 이미지 미리보기와 파일 input 업데이트를 수행합니다.
이렇게 하면 UI가 개선되어 드롭 및 화면 캡쳐 기능을 통해 이미지를 등록할 수 있으며, 서버에서는 새 파일명으로 저장되어 JSON 파일에 저장된 이미지 경로가 업데이트됩니다.
실제 화면에 표시된 결과는 아래와 같다.
가이드레일의 정보를 수정하는 코드도 일부 수정했다.
수정 버튼을 누르면 기존의 이미지를 불러오는 것이 되지 않아서, 코드를 추가했다.
<script>
$(document).ready(function(){
// 수정 버튼 클릭 시: 해당 행의 데이터를 폼에 채워 수정 모드로 전환
$('.editBtn').on('click', function(){
var index = $(this).data('index');
var row = $(this).closest('tr');
var firstitem = row.find('td:eq(1)').text().trim();
var modelName = row.find('td:eq(2)').text().trim();
var checkType = row.find('td:eq(3)').text().trim();
var imageSrc = row.find('td:eq(4) img').attr('src') || '';
$('#firstitem').val(firstitem);
$('#model_name').val(modelName);
$('#check_type').val(checkType);
$('#existing_image').val(imageSrc);
$('#index').val(index);
$('#action').val('update');
$('#submitBtn').text('수정');
// 추가: 기존 이미지가 있으면 previewContainer에 표시
if(imageSrc) {
$('#previewContainer').html('<img src="' + imageSrc + '" alt="이미지" class="img-fluid">');
} else {
$('#previewContainer').html('아직 등록된 이미지가 없습니다.');
}
});
// 삭제 버튼 클릭 시: 확인 후 폼 제출하여 삭제 처리
$('.deleteBtn').on('click', function(){
var index = $(this).data('index');
if(confirm("정말 삭제하시겠습니까?")){
$('#index').val(index);
$('#action').val('delete');
$('#guiderailForm').submit();
}
});
});
</script>
반응형
'IT tech Coding > php' 카테고리의 다른 글
PHP에서 특정 단어가 포함되었는지 확인하는 방법 (0) | 2025.03.04 |
---|---|
계층형 카테고리 관리: MySQL과 PHP로 트리 구조 만들기 (0) | 2025.02.26 |
PHP에서 GET 방식으로 전달된 쿼리 문자열 안전하게 처리하기 (0) | 2025.02.17 |
숫자 입력에서 콤마(,) 제거하는 방법 - JavaScript와 PHP 코드 예제 (0) | 2025.02.10 |
PHP에서 브라켓 품목코드 기반 재고 조회 기능 구현하기 (0) | 2025.02.06 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 구글드라이브API
- #웹개발
- json파일형태보기
- #데이터무결성
- 프로그래머생활
- 엑셀보호
- 오토핫키가이드
- 캐드자동작도
- coalesce는 한국어로 "코얼레스크" 또는 "코얼리스"
- 엑셀입력보호
- #트리구조
- 테크에능한여성
- Bootstrap 5
- #동적ui
- 효율적코딩방법
- #카테고리트리
- 엑셀셀보호
- 스크립트작성기초
- ajax오류메시지
- General error: 2031
- 1. #웹개발 2. #로트번호 3. #성적서보기 4. #ajax 5. #jquery 6. #php 7. #프론트엔드 8. #백엔드 9. #부트스트랩 10. #웹기능구현
- 코딩튜토리얼
- 뫄프로그래밍
- #계층형데이터
- isset을 적용해야 하는 이유
- 오블완
- 티스토리챌린지
- json파일편하게보는법
- #데이터베이스설계
- 도면자동생성
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
글 보관함