Nginx 가계부 코드 작성 요청
간단한 인사 나누기
어떤 모델이 더 좋을까?
제미니와의 첫 대화
앱 설치 가이드 (Android 중심)
더보기
# Gems
브레인스토밍 도우미
커리어 컨설턴트
코딩 파트너
더보기
대한민국 경기도 화성시 봉담읍 삼천병마로
IP 주소 기반 • 위치 업데이트
# Gemini와의 대화
nginx, php7.4, mariadb로 작동하는 간단한 가계부 코드 작성해줘
## nginx, PHP 7.4, MariaDB로 작동하는 간단한 가계부 코드
다음은 nginx, PHP 7.4, MariaDB 환경에서 작동하는 매우 간단한 가계부 코드입니다. 이 코드는 기본적인 수입/지출 기록, 조회, 합계 기능을 제공하며, 실제 사용을 위해서는 보안, 유효성 검사, 사용자 인터페이스 개선 등 추가적인 작업이 필요합니다.
**1. MariaDB 데이터베이스 설정:**
먼저 가계부 데이터를 저장할 데이터베이스와 테이블을 생성합니다. MariaDB에 접속하여 다음 SQL 명령어를 실행합니다.
SQL
```
CREATE DATABASE IF NOT EXISTS my_account_book;
USE my_account_book;
CREATE TABLE IF NOT EXISTS transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
type ENUM('income', 'expense') NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
description VARCHAR(255),
transaction_date DATE NOT NULL DEFAULT CURRENT_DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
**2. PHP 코드 (index.php):**
다음은 가계부 기능을 처리하는 `index.php` 파일의 내용입니다.
PHP
```
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("데이터베이스 연결 실패: " . $e->getMessage());
}
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
$type = $_POST['type'];
$amount = $_POST['amount'];
$description = $_POST['description'];
$transaction_date = $_POST['transaction_date'];
if (in_array($type, ['income', 'expense']) && is_numeric($amount) && $amount > 0) {
$stmt = $pdo->prepare("INSERT INTO transactions (type, amount, description, transaction_date) VALUES (:type, :amount, :description, :transaction_date)");
$stmt->bindParam(':type', $type);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':transaction_date', $transaction_date);
$stmt->execute();
$message = "기록이 추가되었습니다.";
} else {
$error = "입력값이 올바르지 않습니다.";
}
} elseif ($action === 'delete' && isset($_POST['id'])) {
$id = $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$message = "기록이 삭제되었습니다.";
}
}
}
// 전체 기록 조회
$stmt = $pdo->query("SELECT * FROM transactions ORDER BY transaction_date DESC");
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 수입 합계
$stmt = $pdo->query("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income'");
$total_income_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_income = $total_income_result['total_income'] ?? 0;
// 지출 합계
$stmt = $pdo->query("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense'");
$total_expense_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_expense = $total_expense_result['total_expense'] ?? 0;
// 순이익
$net_profit = $total_income - $total_expense;
?>
```
**3. Nginx 설정:**
Nginx 설정 파일 (예: `/etc/nginx/sites-available/default`)에서 PHP 파일을 처리하도록 PHP-FPM과 연결하는 설정을 추가해야 합니다.
Nginx
```
server {
listen 80;
server_name your_domain.com; # 실제 도메인 또는 IP 주소로 변경
root /var/www/your_project_directory; # PHP 파일이 위치할 디렉토리로 변경
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # PHP 버전에 맞는 소켓 경로 확인
}
location ~ /\.ht {
deny all;
}
}
```
**주의사항:**
- **데이터베이스 정보 수정:** `index.php` 파일에서 `$host`, `$dbname`, `$username`, `$password` 변수를 실제 MariaDB 설정에 맞게 수정해야 합니다.
- **PHP-FPM 소켓 경로 확인:** Nginx 설정에서 `fastcgi_pass` 부분을 실제 PHP-FPM 소켓 경로로 확인하고 수정해야 합니다. PHP 버전에 따라 경로가 다를 수 있습니다.
- **파일 저장 경로:** PHP 파일을 Nginx `root` 디렉토리 아래에 저장해야 합니다. 예를 들어 `/var/www/your_project_directory/index.php` 와 같이 저장합니다.
- **Nginx 설정 적용:** Nginx 설정 파일을 수정한 후에는 Nginx를 재시작해야 변경 사항이 적용됩니다 (`sudo systemctl restart nginx`).
- **보안:** 이 코드는 기본적인 기능만 제공하며, 실제 사용 환경에서는 SQL 인젝션, XSS 공격 등에 취약할 수 있습니다. 입력값 검증, Prepared Statements 사용, HTTPS 적용 등 보안 강화를 위한 추가적인 작업이 필요합니다.
- **오류 처리:** 간단한 오류 메시지만을 제공하므로, 실제 환경에서는 더 상세한 오류 로깅 및 사용자 친화적인 오류 처리 방식을 구현하는 것이 좋습니다.
- **UI 개선:** HTML과 CSS만으로 기본적인 UI를 제공하므로, 필요에 따라 JavaScript, CSS 프레임워크 등을 사용하여 사용자 인터페이스를 개선할 수 있습니다.
위 코드를 통해 기본적인 가계부 기능을 구현하고, 필요에 따라 기능을 확장하고 개선해 나가실 수 있습니다.
삭제 코드도 만들어줘
알겠습니다. 기존 `index.php` 코드에 삭제 기능을 추가하는 코드를 포함해 드렸습니다.
**수정된 PHP 코드 (index.php):**
PHP
```
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("데이터베이스 연결 실패: " . $e->getMessage());
}
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
$type = $_POST['type'];
$amount = $_POST['amount'];
$description = $_POST['description'];
$transaction_date = $_POST['transaction_date'];
if (in_array($type, ['income', 'expense']) && is_numeric($amount) && $amount > 0) {
$stmt = $pdo->prepare("INSERT INTO transactions (type, amount, description, transaction_date) VALUES (:type, :amount, :description, :transaction_date)");
$stmt->bindParam(':type', $type);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':transaction_date', $transaction_date);
$stmt->execute();
$message = "기록이 추가되었습니다.";
} else {
$error = "입력값이 올바르지 않습니다.";
}
} elseif ($action === 'delete' && isset($_POST['id'])) {
$id = $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$message = "기록이 삭제되었습니다.";
}
}
}
// 전체 기록 조회
$stmt = $pdo->query("SELECT * FROM transactions ORDER BY transaction_date DESC");
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 수입 합계
$stmt = $pdo->query("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income'");
$total_income_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_income = $total_income_result['total_income'] ?? 0;
// 지출 합계
$stmt = $pdo->query("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense'");
$total_expense_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_expense = $total_expense_result['total_expense'] ?? 0;
// 순이익
$net_profit = $total_income - $total_expense;
?>
간단한 가계부
```
**추가된 부분에 대한 설명:**
1. **POST 요청 처리:**
- `if ($_SERVER['REQUEST_METHOD'] === 'POST')` 블록 안에서 `$_POST['action']` 값을 확인합니다.
- `$action === 'delete'` 인 경우, `$_POST['id']` 값을 가져와 삭제할 레코드의 ID로 사용합니다.
2. **삭제 쿼리 실행:**
- `$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");` SQL DELETE 문을 준비합니다.
- `$stmt->bindParam(':id', $id, PDO::PARAM_INT);` 삭제할 ID 값을 바인딩합니다. `PDO::PARAM_INT`는 해당 값이 정수형임을 명시하여 보안을 강화합니다.
- `$stmt->execute();` 쿼리를 실행하여 데이터베이스에서 해당 레코드를 삭제합니다.
- 삭제 성공 시 `$message` 변수에 "기록이 삭제되었습니다." 메시지를 저장합니다.
3. **삭제 버튼 추가:**
- 기록 조회 테이블의 각 행에 삭제 버튼을 포함하는 `
` 아래에 시작일(`start_date`)과 종료일(`end_date`)을 입력받는 폼이 추가되었습니다.
- 폼 제출 시 `action` hidden 필드 값은 `filter`로 설정됩니다.
- **POST 요청 처리 (`action === 'filter'`):**
- `$_POST['action']` 값이 `filter`인 경우, `$_POST['start_date']`와 `$_POST['end_date']` 값을 가져옵니다.
- **유효성 검사:** 시작일과 종료일이 비어있지 않고, 시작일이 종료일보다 이전이거나 같은 경우에만 데이터베이스 조회를 수행합니다.
- **기간별 조회 쿼리:**
- `SELECT * FROM transactions WHERE transaction_date >= :start_date AND transaction_date <= :end_date ORDER BY transaction_date DESC` 쿼리를 사용하여 지정된 기간 내의 거래 내역을 조회합니다.
- `bindParam()`을 사용하여 시작일과 종료일을 바인딩합니다.
- **기간별 합계 계산:**
- 기간 내 수입 합계와 지출 합계를 별도의 쿼리로 계산합니다.
- **결과 메시지 및 오류 메시지:**
- 조회 성공 시 `$filter_message`에 조회 기간을 표시하는 메시지를 저장합니다.
- 조회 기간 선택이 잘못된 경우 `$filter_error`에 오류 메시지를 저장하고, 전체 기록을 다시 조회하여 표시합니다.
- **초기 페이지 로딩:**
- POST 요청이 없을 경우 (페이지 처음 로딩 시) 전체 거래 내역과 합계를 조회하여 표시합니다.
- **스타일 변경:**
- 기간별 조회 폼 관련 CSS 스타일(`.filter-form`, `.filter-message`, `.filter-error`)을 추가하여 UI를 개선했습니다.
**사용 방법:**
1. 수정된 `index.php` 파일을 웹 서버에 저장합니다.
2. 웹 브라우저를 통해 해당 페이지에 접속합니다.
3. "기간별 조회" 폼에서 원하는 시작일과 종료일을 선택하고 "조회" 버튼을 클릭합니다.
4. 선택한 기간 동안의 거래 내역과 해당 기간의 총 수입, 총 지출, 순이익이 표시됩니다.
5. 기간 선택이 잘못된 경우 오류 메시지가 표시되고, 전체 기록이 다시 표시됩니다.
이제 일정 기간 동안의 가계부 내역을 편리하게 조회할 수 있습니다. 필요에 따라 조회 결과에 대한 추가적인 필터링 (예: 수입/지출별 조회) 기능을 구현할 수도 있습니다.
오류발생했어 오류수정해줘
어떤 종류의 오류가 발생했는지 알려주시면 오류를 수정하는 데 도움이 됩니다.
**오류 메시지, 발생 상황, 증상 등을 자세히 알려주세요.** 예를 들어 다음과 같은 정보를 알려주시면 좋습니다.
- **화면에 표시되는 오류 메시지 내용:** (PHP 오류, MariaDB 오류, Nginx 오류 등)
- **어떤 동작을 했을 때 오류가 발생했는지:** (기록 추가, 삭제, 기간 조회 등)
- **오류가 발생했을 때의 증상:** (페이지가 하얗게 나오는지, 특정 기능만 작동하지 않는지 등)
- **브라우저 개발자 도구 (F12)의 Console 또는 Network 탭에 나타나는 오류:** (JavaScript 오류, HTTP 상태 코드 등)
일반적으로 발생할 수 있는 몇 가지 오류와 그에 대한 সম্ভাব্য 해결 방법을 먼저 제시해 드릴 테니 확인해 보시고, 그래도 해결되지 않으면 더 자세한 오류 정보를 알려주세요.
**일반적인 오류 및 해결 방법:**
1. **데이터베이스 연결 오류:**
- `데이터베이스 연결 실패: ...` 와 같은 오류 메시지가 표시된다면 `index.php` 파일의 데이터베이스 연결 설정 (`$host`, `$dbname`, `$username`, `$password`)이 MariaDB 설정과 일치하는지 확인하세요.
- MariaDB 서버가 실행 중인지 확인하세요.
2. **SQL 오류:**
- `PDOException`과 함께 SQL 구문 오류 관련 메시지가 표시된다면, `index.php` 파일의 SQL 쿼리 (INSERT, DELETE, SELECT) 구문을 다시 한번 확인해 보세요. 오타나 문법 오류가 있을 수 있습니다.
- 특히 기간 조회 쿼리에서 `transaction_date` 컬럼명이 정확한지 확인하세요.
3. **PHP 문법 오류:**
- 페이지가 하얗게 나오거나 `Parse error`와 같은 메시지가 표시된다면 `index.php` 파일에 PHP 문법 오류가 있을 가능성이 큽니다. 코드 편집기의 오류 검사 기능을 이용하거나, PHP 오류 로깅 설정을 확인하여 오류 내용을 파악하고 수정하세요.
4. **변수명 오류:**
- 정의되지 않은 변수를 사용하려고 할 때 오류가 발생할 수 있습니다. 예를 들어 기간 조회 후 합계 변수 (`$total_income`, `$total_expense`, `$net_profit`)가 제대로 초기화되지 않아 오류가 발생할 수 있습니다. 코드에서 변수명을 정확하게 사용했는지 확인하세요.
5. **POST 데이터 처리 오류:**
- 폼에서 데이터를 전송했는데 PHP에서 제대로 받지 못하는 경우, 폼의 `name` 속성과 PHP 코드의 `$_POST` 배열 키 값이 일치하는지 확인하세요.
6. **Nginx 설정 오류:**
- PHP 파일이 제대로 실행되지 않거나 다운로드되는 경우, Nginx 설정 파일 (`/etc/nginx/sites-available/default` 등)에서 PHP-FPM 연결 설정 (`fastcgi_pass`)이 올바르게 되어 있는지, PHP 버전에 맞는 소켓 경로를 사용하고 있는지 확인하고 Nginx를 재시작하세요 (`sudo systemctl restart nginx`).
**오류 메시지와 관련 상황을 자세히 알려주시면 더욱 정확하게 문제 해결을 도와드릴 수 있습니다.**
Warning: Undefined variable $total_income in /volume1/web/index.php on line 220
알려주신 오류 메시지는 `Warning: Undefined variable $total_income in /volume1/web/index.php on line 220` 이고, 이는 `$total_income` 변수가 해당 라인에서 정의되지 않았다는 경고입니다. 이 오류는 주로 변수가 선언되거나 값이 할당되기 전에 사용하려고 할 때 발생합니다.
제공해주신 코드 전체를 다시 살펴보니, 기간 조회(`action === 'filter'`) 시에만 `$total_income`, `$total_expense`, `$net_profit` 변수를 계산하고 있습니다. 따라서 초기 페이지 로딩 시나 기간 조회 조건이 맞지 않아 전체 데이터를 다시 조회하는 경우에는 이 변수들이 정의되지 않아 경고가 발생할 수 있습니다.
**수정 방법:**
초기 페이지 로딩 시와 기간 조회 실패 시에도 `$total_income`, `$total_expense`, `$net_profit` 변수를 계산하도록 코드를 수정해야 합니다.
다음과 같이 `index.php` 파일을 수정해 보세요.
PHP
```
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("데이터베이스 연결 실패: " . $e->getMessage());
}
// 변수 초기화
$transactions = [];
$total_income = 0;
$total_expense = 0;
$net_profit = 0;
$message = '';
$error = '';
$filter_message = '';
$filter_error = '';
// 입력 처리 및 기간 조회 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
$type = $_POST['type'];
$amount = $_POST['amount'];
$description = $_POST['description'];
$transaction_date = $_POST['transaction_date'];
if (in_array($type, ['income', 'expense']) && is_numeric($amount) && $amount > 0) {
$stmt = $pdo->prepare("INSERT INTO transactions (type, amount, description, transaction_date) VALUES (:type, :amount, :description, :transaction_date)");
$stmt->bindParam(':type', $type);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':transaction_date', $transaction_date);
$stmt->execute();
$message = "기록이 추가되었습니다.";
} else {
$error = "입력값이 올바르지 않습니다.";
}
} elseif ($action === 'delete' && isset($_POST['id'])) {
$id = $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$message = "기록이 삭제되었습니다.";
} elseif ($action === 'filter') {
$start_date = $_POST['start_date'];
$end_date = $_POST['end_date'];
if (!empty($start_date) && !empty($end_date) && $start_date <= $end_date) {
$stmt = $pdo->prepare("SELECT * FROM transactions WHERE transaction_date >= :start_date AND transaction_date <= :end_date ORDER BY transaction_date DESC");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 기간 조회 합계
$stmt_income = $pdo->prepare("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_income->bindParam(':start_date', $start_date);
$stmt_income->bindParam(':end_date', $end_date);
$stmt_income->execute();
$total_income_result = $stmt_income->fetch(PDO::FETCH_ASSOC);
$total_income = $total_income_result['total_income'] ?? 0;
$stmt_expense = $pdo->prepare("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_expense->bindParam(':start_date', $start_date);
$stmt_expense->bindParam(':end_date', $end_date);
$stmt_expense->execute();
$total_expense_result = $stmt_expense->fetch(PDO::FETCH_ASSOC);
$total_expense = $total_expense_result['total_expense'] ?? 0;
$net_profit = $total_income - $total_expense;
$filter_message = "{$start_date} ~ {$end_date} 기간 조회 결과";
} else {
$filter_error = "조회 기간을 올바르게 선택해주세요.";
// 전체 기록 다시 조회
$stmt = $pdo->query("SELECT * FROM transactions ORDER BY transaction_date DESC");
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = $pdo->query("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income'");
$total_income_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_income = $total_income_result['total_income'] ?? 0;
$stmt = $pdo->query("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense'");
$total_expense_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_expense = $total_expense_result['total_expense'] ?? 0;
$net_profit = $total_income - $total_expense;
}
}
}
} else {
// 초기 페이지 로딩 시 전체 기록 조회 및 합계 계산
$stmt = $pdo->query("SELECT * FROM transactions ORDER BY transaction_date DESC");
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = $pdo->query("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income'");
$total_income_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_income = $total_income_result['total_income'] ?? 0;
$stmt = $pdo->query("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense'");
$total_expense_result = $stmt->fetch(PDO::FETCH_ASSOC);
$total_expense = $total_expense_result['total_expense'] ?? 0;
$net_profit = $total_income - $total_expense;
}
?>
간단한 가계부
```
**수정된 부분:**
- **변수 초기화:** 코드 상단에 `$transactions = []`, `$total_income = 0`, `$total_expense = 0`, `$net_profit = 0` 와 같이 관련 변수들을 초기화했습니다. 이렇게 하면 어떤 경우에도 해당 변수들이 정의되어 있게 됩니다.
- **초기 페이지 로딩 시 합계 계산 유지:** `else` 블록 (POST 요청이 없을 경우)에서 전체 기록을 조회한 후에도 수입, 지출, 순이익 합계를 계산하는 코드가 그대로 유지됩니다.
- **기간 조회 실패 시 합계 계산 유지:** 기간 조회 조건이 맞지 않아 전체 기록을 다시 조회하는 경우에도 합계를 계산하는 코드가 유지됩니다.
이렇게 수정하면 `$total_income` 변수가 항상 정의되어 있으므로 `Undefined variable` 경고가 사라질 것입니다.
수정 후에도 동일한 오류가 발생하거나 다른 오류가 발생하면 다시 알려주세요. 오류 메시지와 함께 어떤 동작을 했을 때 발생했는지 자세히 알려주시면 문제 해결에 더욱 도움이 됩니다.
조회기간이 고정되게하고, 삭제할때 초기화 되지 않게 코드 수정해줘
알겠습니다. 조회 기간을 고정하고, 삭제 시 조회 결과가 초기화되지 않도록 코드를 수정해 드리겠습니다.
**1. PHP 코드 수정 (index.php):**
PHP
```
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("데이터베이스 연결 실패: " . $e->getMessage());
}
// 변수 초기화
$transactions = [];
$total_income = 0;
$total_expense = 0;
$net_profit = 0;
$message = '';
$error = '';
$filter_message = '';
$filter_error = '';
// 고정 조회 기간 설정 (YYYY-MM-DD 형식)
$fixed_start_date = '2024-01-01'; // 예시: 2024년 1월 1일부터
$fixed_end_date = date('Y-m-d'); // 현재 날짜까지
// 기간 조회 함수
function getTransactionsByPeriod($pdo, $start_date, $end_date) {
$stmt = $pdo->prepare("SELECT * FROM transactions WHERE transaction_date >= :start_date AND transaction_date <= :end_date ORDER BY transaction_date DESC");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 합계 계산 함수
function calculateTotalsByPeriod($pdo, $start_date, $end_date) {
$totals = ['income' => 0, 'expense' => 0, 'net_profit' => 0];
$stmt_income = $pdo->prepare("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_income->bindParam(':start_date', $start_date);
$stmt_income->bindParam(':end_date', $end_date);
$stmt_income->execute();
$total_income_result = $stmt_income->fetch(PDO::FETCH_ASSOC);
$totals['income'] = $total_income_result['total_income'] ?? 0;
$stmt_expense = $pdo->prepare("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_expense->bindParam(':start_date', $start_date);
$stmt_expense->bindParam(':end_date', $end_date);
$stmt_expense->execute();
$total_expense_result = $stmt_expense->fetch(PDO::FETCH_ASSOC);
$totals['expense'] = $total_expense_result['total_expense'] ?? 0;
$totals['net_profit'] = $totals['income'] - $totals['expense'];
return $totals;
}
// 초기 데이터 로드 (고정 기간)
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
$filter_message = "{$fixed_start_date} ~ {$fixed_end_date} 기간 조회";
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
$type = $_POST['type'];
$amount = $_POST['amount'];
$description = $_POST['description'];
$transaction_date = $_POST['transaction_date'];
if (in_array($type, ['income', 'expense']) && is_numeric($amount) && $amount > 0) {
$stmt = $pdo->prepare("INSERT INTO transactions (type, amount, description, transaction_date) VALUES (:type, :amount, :description, :transaction_date)");
$stmt->bindParam(':type', $type);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':transaction_date', $transaction_date);
$stmt->execute();
$message = "기록이 추가되었습니다.";
// 추가 후에도 고정 기간 데이터 다시 로드
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
} else {
$error = "입력값이 올바르지 않습니다.";
}
} elseif ($action === 'delete' && isset($_POST['id'])) {
$id = $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$message = "기록이 삭제되었습니다.";
// 삭제 후에도 고정 기간 데이터 다시 로드
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
}
}
}
?>
간단한 가계부
```
**2. 변경된 부분에 대한 설명:**
- **고정 조회 기간 설정:**
- `$fixed_start_date` 변수를 추가하여 고정된 시작 날짜를 설정합니다. 필요에 따라 값을 변경하세요.
- `$fixed_end_date` 변수를 `date('Y-m-d')`로 설정하여 고정된 종료 날짜를 현재 날짜로 설정합니다. 필요에 따라 다른 날짜로 설정할 수 있습니다.
- **기간 조회 및 합계 계산 함수:**
- `getTransactionsByPeriod()` 함수를 만들어 지정된 기간의 거래 내역을 조회하도록 했습니다.
- `calculateTotalsByPeriod()` 함수를 만들어 지정된 기간의 수입, 지출, 순이익 합계를 계산하도록 했습니다. 이렇게 함수로 분리하여 코드의 재사용성을 높였습니다.
- **초기 데이터 로드 (고정 기간):**
- 페이지가 처음 로드될 때 `getTransactionsByPeriod()`와 `calculateTotalsByPeriod()` 함수를 사용하여 고정된 기간의 데이터를 조회하고 합계를 계산합니다.
- **삭제 및 추가 후 데이터 재로드:**
- 기록이 추가되거나 삭제된 후에는 다시 `getTransactionsByPeriod()`와 `calculateTotalsByPeriod()` 함수를 호출하여 고정된 기간의 데이터를 다시 로드하고 합계를 업데이트합니다. 이렇게 하면 삭제나 추가 작업 후에도 조회 결과가 초기화되지 않고 현재 고정 기간의 데이터가 유지됩니다.
- **기간별 조회 폼 숨김:**
- CSS 스타일을 사용하여 기간 선택 폼 (`.filter-form`)과 관련 메시지 (`.filter-error`)를 숨겼습니다. 이제 사용자는 임의로 조회 기간을 변경할 수 없습니다.
- 고정된 조회 기간을 나타내는 메시지를 `
기간별 조회
` 아래에 표시하도록 수정했습니다.
**사용 방법:**
1. 수정된 `index.php` 파일을 웹 서버에 저장합니다.
2. 웹 브라우저를 통해 해당 페이지에 접속합니다.
3. 이제 페이지를 처음 로드하거나, 기록을 추가/삭제해도 항상 `$fixed_start_date` 부터 `$fixed_end_date` 까지의 거래 내역과 합계가 표시됩니다.
4. 기간별 조회 폼은 화면에 나타나지 않아 사용자는 조회 기간을 변경할 수 없습니다.
이제 조회 기간은 코드에 고정되어 유지되며, 삭제 작업을 수행해도 조회 결과가 초기화되지 않고 현재 고정된 기간의 데이터가 계속 표시될 것입니다. 고정된 조회 기간을 변경하고 싶다면 `$fixed_start_date` 변수의 값을 수정하면 됩니다.
Parse error: syntax error, unexpected end of file, expecting "elseif" or "else" or "endif" in /volume1/web/index.php on line 142
알려주신 오류 메시지 `Parse error: syntax error, unexpected end of file, expecting "elseif" or "else" or "endif" in /volume1/web/index.php on line 142`는 PHP 코드의 문법 오류로, `if` 구문이 제대로 닫히지 않았음을 의미합니다. 142번째 줄에서 파일의 끝(end of file)이 예기치 않게 나타났으며, `elseif`, `else`, 또는 `endif` 중 하나를 예상하고 있다는 내용입니다.
제공해주신 코드의 142번째 줄 주변을 살펴보겠습니다. 해당 줄은 `// 입력 처리` 블록의 `if ($_SERVER['REQUEST_METHOD'] === 'POST')` 구문의 마지막 부분일 가능성이 높습니다. 이 `if` 구문이 제대로 닫히지 않았을 때 해당 오류가 발생합니다.
**수정 방법:**
`if ($_SERVER['REQUEST_METHOD'] === 'POST')` 블록이 `}` (중괄호)로 올바르게 닫혔는지 확인해야 합니다. 코드에서 해당 블록의 시작 부분(`if ($_SERVER['REQUEST_METHOD'] === 'POST') {`)을 찾고, 그에 대응하는 닫는 중괄호 `}`가 있는지 확인하세요.
제공해주신 가장 최근의 코드에서는 142번째 줄 근처에 해당 `if` 블록이 있습니다. 아래는 해당 부분의 코드입니다.
PHP
```
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
// ... (추가 처리 코드) ...
} elseif ($action === 'delete' && isset($_POST['id'])) {
// ... (삭제 처리 코드) ...
}
// elseif ($action === 'filter') { // 이 부분은 이제 없습니다.
// // ... (기간 조회 처리 코드) ...
// }
}
}
?>
```
이 코드 블록은 `if ($_SERVER['REQUEST_METHOD'] === 'POST')` 에 대한 닫는 중괄호가 없습니다.
**수정해야 할 부분:**
`// 입력 처리` 블록의 마지막에 닫는 중괄호 `}`를 추가해야 합니다.
**수정된 코드 (해당 부분):**
PHP
```
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
// ... (추가 처리 코드) ...
} elseif ($action === 'delete' && isset($_POST['id'])) {
// ... (삭제 처리 코드) ...
}
// elseif ($action === 'filter') { // 이 부분은 이제 없습니다.
// // ... (기간 조회 처리 코드) ...
// }
}
} // <-- 이 닫는 중괄호가 누락되었습니다.
?>
```
**전체 코드에 적용:**
제공해주신 전체 코드에서 `// 입력 처리` 블록의 마지막 부분에 `}` 를 추가하여 `if ($_SERVER['REQUEST_METHOD'] === 'POST')` 구문을 닫아주세요.
**수정 후 확인:**
코드를 수정한 후 파일을 저장하고 웹 페이지를 다시 로드하여 오류가 해결되었는지 확인해 보세요.
만약 위 방법으로 해결되지 않거나 다른 오류가 발생한다면, 다시 한번 오류 메시지와 함께 해당 오류가 발생하는 상황을 자세히 알려주시면 추가적인 도움을 드릴 수 있습니다. 특히 오류가 발생한 정확한 줄 번호와 주변 코드를 함께 알려주시면 문제 해결에 더욱 효과적입니다.
포함해서 코드 다시 작성해줘
PHP
```
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("데이터베이스 연결 실패: " . $e->getMessage());
}
// 변수 초기화
$transactions = [];
$total_income = 0;
$total_expense = 0;
$net_profit = 0;
$message = '';
$error = '';
$filter_message = '';
$filter_error = '';
// 고정 조회 기간 설정 (YYYY-MM-DD 형식)
$fixed_start_date = '2024-01-01'; // 예시: 2024년 1월 1일부터
$fixed_end_date = date('Y-m-d'); // 현재 날짜까지
// 기간 조회 함수
function getTransactionsByPeriod($pdo, $start_date, $end_date) {
$stmt = $pdo->prepare("SELECT * FROM transactions WHERE transaction_date >= :start_date AND transaction_date <= :end_date ORDER BY transaction_date DESC");
$stmt->bindParam(':start_date', $start_date);
$stmt->bindParam(':end_date', $end_date);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 합계 계산 함수
function calculateTotalsByPeriod($pdo, $start_date, $end_date) {
$totals = ['income' => 0, 'expense' => 0, 'net_profit' => 0];
$stmt_income = $pdo->prepare("SELECT SUM(amount) AS total_income FROM transactions WHERE type = 'income' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_income->bindParam(':start_date', $start_date);
$stmt_income->bindParam(':end_date', $end_date);
$stmt_income->execute();
$total_income_result = $stmt_income->fetch(PDO::FETCH_ASSOC);
$totals['income'] = $total_income_result['total_income'] ?? 0;
$stmt_expense = $pdo->prepare("SELECT SUM(amount) AS total_expense FROM transactions WHERE type = 'expense' AND transaction_date >= :start_date AND transaction_date <= :end_date");
$stmt_expense->bindParam(':start_date', $start_date);
$stmt_expense->bindParam(':end_date', $end_date);
$stmt_expense->execute();
$total_expense_result = $stmt_expense->fetch(PDO::FETCH_ASSOC);
$totals['expense'] = $total_expense_result['total_expense'] ?? 0;
$totals['net_profit'] = $totals['income'] - $totals['expense'];
return $totals;
}
// 초기 데이터 로드 (고정 기간)
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
$filter_message = "{$fixed_start_date} ~ {$fixed_end_date} 기간 조회";
// 입력 처리
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add') {
$type = $_POST['type'];
$amount = $_POST['amount'];
$description = $_POST['description'];
$transaction_date = $_POST['transaction_date'];
if (in_array($type, ['income', 'expense']) && is_numeric($amount) && $amount > 0) {
$stmt = $pdo->prepare("INSERT INTO transactions (type, amount, description, transaction_date) VALUES (:type, :amount, :description, :transaction_date)");
$stmt->bindParam(':type', $type);
$stmt->bindParam(':amount', $amount, PDO::PARAM_STR);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':transaction_date', $transaction_date);
$stmt->execute();
$message = "기록이 추가되었습니다.";
// 추가 후에도 고정 기간 데이터 다시 로드
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
} else {
$error = "입력값이 올바르지 않습니다.";
}
} elseif ($action === 'delete' && isset($_POST['id'])) {
$id = $_POST['id'];
$stmt = $pdo->prepare("DELETE FROM transactions WHERE id = :id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$message = "기록이 삭제되었습니다.";
// 삭제 후에도 고정 기간 데이터 다시 로드
$transactions = getTransactionsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$totals = calculateTotalsByPeriod($pdo, $fixed_start_date, $fixed_end_date);
$total_income = $totals['income'];
$total_expense = $totals['expense'];
$net_profit = $totals['net_profit'];
}
}
}
?>
간단한 가계부