safarizone

모든 작성하고 싶어하는 마음으로

플러터(Flutter)에서 PHP를 활용하여 데이터를 서버 파일로 저장하는 심층 가이드

플러터 앱에서 생성된 데이터를 서버에 안전하게 기록하는 과정은 클라이언트(플러터)와 서버(PHP)의 긴밀한 협업을 통해 이루어집니다. 플러터 앱이 데이터를 포장해 보내는 ‘택배 기사’ 역할을 한다면, PHP 스크립트는 이를 받아 검증하고 창고(파일)에 정리하는 ‘물류 관리자’ 역할을 수행합니다. 다음은 이 두 역할에 필요한 스크립트와 그 실행 방법에 대한 상세한 설명입니다.


플러터 클라이언트 스크립트: HTTP 통신을 위한 Dart 코드

플러터 앱은 http 패키지를 사용하여 서버와 통신합니다. 이 스크립트는 사용자가 버튼을 누르면 미리 정의된 데이터를 JSON 형식으로 변환하여 서버에 POST 요청을 보냅니다.

Dart

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert'; // JSON 인코딩/디코딩을 위해 필요

class DataRecorder extends StatefulWidget {
  const DataRecorder({Key? key}) : super(key: key);

  @override
  _DataRecorderState createState() => _DataRecorderState();
}

class _DataRecorderState extends State<DataRecorder> {
  // PHP 스크립트가 배포된 서버의 URL을 정확히 기입합니다.
  final String serverEndpoint = 'http://yourserver.com/save_data.php';

  // 서버에 전송할 데이터를 Map 형태로 정의합니다.
  final Map<String, dynamic> appData = {
    'userName': 'Flutter_Dev',
    'highScore': 2500,
    'lastPlayed': '2025-08-03'
  };

  // 서버로 데이터를 비동기적으로 전송하는 함수
  Future<void> _recordDataOnServer() async {
    // 네트워크 오류에 대비한 예외 처리
    try {
      // POST 요청을 생성하고 헤더에 JSON 형식임을 명시합니다.
      final response = await http.post(
        Uri.parse(serverEndpoint),
        headers: {
          'Content-Type': 'application/json',
        },
        // Dart Map 데이터를 JSON 문자열로 변환하여 요청 본문에 담습니다.
        body: jsonEncode(appData),
      );

      if (response.statusCode == 200) {
        // HTTP 상태 코드가 200이면 성공
        print('데이터 기록 성공: ${response.body}');
      } else {
        // 실패 시 서버 응답과 상태 코드를 출력합니다.
        print('데이터 전송 실패. 응답 코드: ${response.statusCode}');
      }
    } catch (e) {
      // 네트워크 연결 실패 등 예외 발생 시
      print('네트워크 요청 중 오류 발생: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('데이터 서버 기록')),
      body: Center(
        child: ElevatedButton(
          onPressed: _recordDataOnServer,
          child: const Text('데이터 서버로 보내기'),
        ),
      ),
    );
  }
}
  • http.post(): HTTP POST 요청을 시작하는 핵심 함수입니다. Uri.parse()를 통해 URL 문자열을 요청 가능한 객체로 변환합니다.
  • headers: {'Content-Type': 'application/json'}: 서버에 보내는 데이터의 형식이 JSON이라는 것을 미리 알려주는 역할을 합니다. 이는 서버 측 PHP가 데이터를 올바르게 처리하는 데 필수적입니다.
  • body: jsonEncode(appData): Dart의 Map 객체를 서버가 이해할 수 있는 JSON 형식의 문자열로 변환합니다. jsonEncodedart:convert 라이브러리에 포함된 함수입니다.
  • async & await: 서버와 통신하는 과정은 시간이 걸리므로 앱이 멈추지 않도록 비동기적으로 처리해야 합니다. _recordDataOnServer 함수는 async로 선언되었고, http.post 호출에는 await 키워드가 사용되어 응답을 기다립니다.

서버 측 스크립트: 데이터 수신 및 파일 저장 (PHP)

이 PHP 스크립트는 웹 서버에서 동작하며, 유니티 앱이 보낸 JSON 데이터를 수신하고 이를 파일에 추가하는 역할을 담당합니다.

PHP

<?php
header('Content-Type: text/plain; charset=utf-8'); // 응답 헤더 설정

// HTTP 요청 본문(body)의 원시(raw) 데이터를 읽어옵니다.
$raw_json_data = file_get_contents('php://input');

// JSON 문자열을 PHP의 연관 배열로 변환합니다.
$decoded_data = json_decode($raw_json_data, true);

// 데이터를 저장할 파일 이름을 명시적으로 정의합니다.
// 보안을 위해 파일명은 사용자 입력이 아닌 고정값으로 설정합니다.
$log_file = 'game_records.log';

// JSON 데이터가 유효한지 확인합니다.
if ($decoded_data) {
    // 파일에 기록할 최종 문자열을 만듭니다.
    // 가독성을 위해 JSON_PRETTY_PRINT 옵션을 사용합니다.
    $record_entry = json_encode($decoded_data, JSON_PRETTY_PRINT);

    // 파일에 데이터를 추가합니다.
    // FILE_APPEND: 기존 내용에 이어서 씁니다.
    // LOCK_EX: 파일에 쓰는 동안 다른 접근을 막아 데이터 충돌을 방지합니다.
    $write_result = file_put_contents($log_file, $record_entry . ",\n", FILE_APPEND | LOCK_EX);

    if ($write_result !== false) {
        // 성공적으로 기록되면 HTTP 200 OK 상태 코드와 함께 성공 메시지를 보냅니다.
        http_response_code(200);
        echo "데이터가 서버에 성공적으로 기록되었습니다.";
    } else {
        // 파일 쓰기 실패 시 HTTP 500 Internal Server Error와 함께 메시지를 보냅니다.
        http_response_code(500);
        echo "서버 파일 기록에 실패했습니다.";
    }
} else {
    // 유효하지 않은 데이터가 수신된 경우, HTTP 400 Bad Request와 함께 메시지를 보냅니다.
    http_response_code(400);
    echo "유효하지 않은 데이터입니다.";
}
?>
  • file_get_contents('php://input'): PHP는 $_POST 변수로 데이터를 받지만, 플러터가 보내는 JSON 데이터는 $_POST에 직접 담기지 않습니다. 이 함수를 사용하면 HTTP 요청의 원시 본문을 그대로 읽어올 수 있습니다.
  • json_decode(): 읽어온 JSON 형식의 문자열을 PHP가 처리할 수 있는 배열 또는 객체 형태로 변환합니다. true 매개변수는 연관 배열로 변환하라는 의미입니다.
  • file_put_contents(): 파일에 데이터를 기록하는 가장 간단하고 안전한 방법입니다. FILE_APPEND는 파일의 기존 내용 뒤에 새로운 내용을 추가하며, LOCK_EX는 여러 요청이 동시에 들어올 때 데이터가 겹치거나 손상되는 것을 막아줍니다.

시스템 구축을 위한 준비 및 실행 단계

  1. PHP 파일 배포: 작성한 save_data.php 파일을 웹 서버의 공개된 디렉터리에 업로드합니다. 서버에 따라 파일 권한 설정(chmod)이 필요할 수 있습니다.
  2. 플러터 패키지 설치: pubspec.yaml 파일에 http: ^1.0.0 라인을 추가하고, 터미널에서 flutter pub get 명령어를 실행하여 패키지를 다운로드합니다.
  3. URL 설정: 플러터 스크립트의 serverEndpoint 변수에 PHP 파일의 실제 웹 URL을 정확하게 입력해야 합니다. (예: “http://my-website.com/api/save_data.php“)
  4. 실행 및 테스트: 플러터 앱을 실행하고 데이터 전송 버튼을 누르면, 서버에 game_records.log 파일이 생성되거나 업데이트되는 것을 확인할 수 있습니다.이 과정을 통해 플러터 앱과 웹 서버 간에 안정적이고 효율적인 데이터 전송 및 저장 시스템을 구축할 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다