Google Sheets API를 PHP에서 사용해야 하는 이유

 

많은 개발자들이 데이터를 관리할 때 데이터베이스만 생각한다. 하지만 클라이언트나 비즈니스팀에서 "구글 시트에서 직접 수정할 수 있게 해달라"는 요청을 받으면 답답해진다. Google Sheets API를 모르면 매번 CSV 파일을 받아 수동으로 처리하거나, 별도의 관리 페이지를 만들어야 한다.

다만 대부분의 개발자들은 Google Sheets API의 인증 과정이 복잡하다고 생각해서 포기하거나, 공식 문서만 보고 실제 구현에서 막힌다. 이번에는 처음부터 끝까지 Google Sheets API를 PHP에서 어떻게 설정하고, 데이터를 읽고 쓰는지 완벽하게 정리해서 소개하겠다.

1단계: Google Cloud 프로젝트 생성 및 Sheets API 활성화

 

Google Cloud Console 접속
https://console.cloud.google.com 에 접속해서 구글 계정으로 로그인한다. 상단의 프로젝트 선택 드롭다운을 클릭하고 "새 프로젝트"를 만든다.

Sheets API 활성화
좌측 메뉴에서 "API 및 서비스" → "라이브러리"로 이동한다. 검색창에 "Google Sheets API"를 입력해서 찾은 후 클릭해서 "활성화"를 누른다.

서비스 계정 생성
"API 및 서비스" → "사용자 인증 정보"로 이동한다. 상단의 "+ 사용자 인증 정보 만들기"를 클릭하고 "서비스 계정"을 선택한다. 서비스 계정의 이름을 입력하고 (예: sheets-api) 계속 진행한다.

2단계: JSON 키 파일 다운로드

 

생성한 서비스 계정을 클릭해서 상세 페이지로 이동한다. "키" 탭에서 "키 추가" → "새 키 만들기"를 선택하고 "JSON" 형식으로 다운로드한다. 이 파일은 매우 중요하므로 안전한 폴더에 보관하고 절대 깃허브에 커밋하지 말자.

다운로드한 JSON 파일의 구조는 다음과 같다:

{
  "type": "service_account",
  "project_id": "your-project-id",
  "private_key_id": "...",
  "private_key": "-----BEGIN PRIVATE KEY-----n...n-----END PRIVATE KEY-----n",
  "client_email": "sheets-api@your-project-id.iam.gserviceaccount.com",
  "client_id": "...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "..."
}
3단계: PHP에서 Google Sheets API 클라이언트 라이브러리 설치

 

Composer를 사용해서 Google API 클라이언트 라이브러리를 설치한다:

composer require google/apiclient

설치 후 vendor 폴더가 생성되면, 다음과 같이 로드할 수 있다:

require 'vendor/autoload.php';
4단계: 스프레드시트 데이터 읽기

 

기본 구조 이해하기
Google Sheets는 "스프레드시트 ID" (URL에서 /d/ 다음 부분)와 "범위" (시트 이름!A1:Z100 형태)로 데이터를 식별한다.

✗ 잘못된 방법: 키 파일 경로를 하드코딩

$client = new Google_Client();
$client->setAuthConfig('service-account-key.json'); // 웹루트에 파일이 노출될 위험

✓ 올바른 방법: 환경변수에서 로드

<?php
require 'vendor/autoload.php';

use Google_Client;
use Google_Service_Sheets;

$keyFilePath = dirname(__DIR__) . '/config/service-account-key.json'; // 웹루트 외부

$client = new Google_Client();
$client->setAuthConfig($keyFilePath);
$client->addScope(Google_Service_Sheets::SPREADSHEETS);

$service = new Google_Service_Sheets($client);

$spreadsheetId = '당신의_스프레드시트_ID';
$range = 'Sheet1!A1:D10'; // Sheet1의 A1부터 D10까지

try {
    $response = $service->spreadsheets_values->get($spreadsheetId, $range);
    $values = $response->getValues();
    
    if (empty($values)) {
        echo "데이터가 없습니다.";
    } else {
        foreach ($values as $row) {
            echo implode(" | ", $row) . "<br />";
        }
    }
} catch (Exception $e) {
    echo "오류: " . $e->getMessage();
}
?>

결과: Sheet1의 첫 10행 데이터가 출력된다.

5단계: 스프레드시트에 데이터 쓰기

 

✗ 잘못된 방법: 값을 그냥 배열로 전달

$values = [
    ['John', 'Developer', '2024-01-15'],
    ['Jane', 'Designer', '2024-01-16']
];

$service->spreadsheets_values->update($spreadsheetId, $range, $values);
// ValueInputOption을 지정하지 않으면 오류 발생

✓ 올바른 방법: ValueInputOption 지정

<?php
require 'vendor/autoload.php';

use Google_Client;
use Google_Service_Sheets;
use Google_Service_Sheets_ValueRange;

$keyFilePath = dirname(__DIR__) . '/config/service-account-key.json';

$client = new Google_Client();
$client->setAuthConfig($keyFilePath);
$client->addScope(Google_Service_Sheets::SPREADSHEETS);

$service = new Google_Service_Sheets($client);

$spreadsheetId = '당신의_스프레드시트_ID';
$range = 'Sheet1!A2'; // A2부터 데이터 입력

$values = new Google_Service_Sheets_ValueRange([
    'values' => [
        ['John', 'Developer', '2024-01-15'],
        ['Jane', 'Designer', '2024-01-16'],
        ['Bob', 'Manager', '2024-01-17']
    ]
]);

$options = ['valueInputOption' => 'RAW']; // RAW: 값 그대로, USER_ENTERED: 공식도 실행

try {
    $response = $service->spreadsheets_values->update(
        $spreadsheetId,
        $range,
        $values,
        $options
    );
    echo "성공! " . $response->getUpdatedRows() . "행이 업데이트되었습니다.";
} catch (Exception $e) {
    echo "오류: " . $e->getMessage();
}
?>

결과: 3행의 데이터가 Sheet1의 A2부터 입력된다.

6단계: 중요한 주의사항과 흔한 실수

 

문제 원인 해결책
"Access Denied" 오류 서비스 계정이 스프레드시트에 접근 권한이 없음 스프레드시트를 공유할 때 서비스 계정 이메일(client_email)을 초대로 추가
"Invalid Spreadsheet ID" 오류 스프레드시트 ID가 잘못됨 구글 시트 URL에서 /d/ 다음 부분을 정확히 복사. 예: /d/ABC123XYZ/edit → ABC123XYZ
데이터가 입력되지 않음 범위 지정 오류 또는 valueInputOption 누락 범위를 'Sheet1!A1' 형태로 명시하고, valueInputOption을 'RAW' 또는 'USER_ENTERED'로 지정
한글이 깨져서 출력됨 문자 인코딩 설정 누락 PHP 파일 상단에 header('Content-Type: text/html; charset=utf-8'); 추가
7단계: 실전 예제 - 회원 정보 동기화

 

실제 프로젝트에서 데이터베이스의 사용자 정보를 구글 시트에 자동으로 동기화하는 예제다:

<?php
require 'vendor/autoload.php';

use Google_Client;
use Google_Service_Sheets;
use Google_Service_Sheets_ValueRange;

class SheetsSyncManager {
    private $service;
    private $spreadsheetId;
    
    public function __construct($keyFilePath, $spreadsheetId) {
        $client = new Google_Client();
        $client->setAuthConfig($keyFilePath);
        $client->addScope(Google_Service_Sheets::SPREADSHEETS);
        $this->service = new Google_Service_Sheets($client);
        $this->spreadsheetId = $spreadsheetId;
    }
    
    public function syncUsers($users) {
        // $users는 데이터베이스에서 가져온 배열
        // 형식: [['name' => 'John', 'email' => 'john@example.com', 'created' => '2024-01-15'], ...]
        
        $rows = [['이름', '이메일', '가입일']]; // 헤더
        
        foreach ($users as $user) {
            $rows[] = [
                $user['name'],
                $user['email'],
                $user['created']
            ];
        }
        
        $body = new Google_Service_Sheets_ValueRange([
            'values' => $rows
        ]);
        
        try {
            $this->service->spreadsheets_values->update(
                $this->spreadsheetId,
                'Users!A1',
                $body,
                ['valueInputOption' => 'RAW']
            );
            return true;
        } catch (Exception $e) {
            error_log("Sheets Sync Error: " . $e->getMessage());
            return false;
        }
    }
    
    public function getUsers() {
        try {
            $response = $this->service->spreadsheets_values->get(
                $this->spreadsheetId,
                'Users!A2:C100'
            );
            return $response->getValues() ?? [];
        } catch (Exception $e) {
            error_log("Sheets Read Error: " . $e->getMessage());
            return [];
        }
    }
}

// 사용 예
$manager = new SheetsSyncManager(
    dirname(__DIR__) . '/config/service-account-key.json',
    'your-spreadsheet-id'
);

// DB에서 가져온 사용자 데이터
$users = [
    ['name' => 'John Doe', 'email' => 'john@example.com', 'created' => '2024-01-15'],
    ['name' => 'Jane Smith', 'email' => 'jane@example.com', 'created' => '2024-01-16']
];

if ($manager->syncUsers($users)) {
    echo "사용자 정보가 동기화되었습니다.";
} else {
    echo "동기화 실패.";
}

// 시트에서 데이터 읽기
$sheetUsers = $manager->getUsers();
var_dump($sheetUsers);
?>

이 클래스의 장점:

  • API 호출을 재사용 가능한 메서드로 캡슐화
  • try-catch로 오류를 안전하게 처리
  • 여러 시트를 다루기 쉬운 구조
  • error_log로 문제 추적 가능
8단계: 보안 체크리스트

 

  • JSON 키 파일: 웹루트 외부에 저장. .gitignore에 추가해서 깃에 커밋되지 않게 하기
  • 서비스 계정 이메일: 필요한 스프레드시트에만 공유. 과도한 권한 부여 피하기
  • API 호출 로깅: 누가, 언제, 어떤 데이터를 수정했는지 기록
  • Rate Limiting: 구글 API는 분당 요청 수 제한이 있으므로 대량 작업 시 딜레이 추가
  • 캐싱: 자주 읽는 데이터는 로컬에 캐시해서 API 호출 횟수 감소
마무리: 작은 자동화가 만드는 큰 효과

 

Google Sheets API와 PHP의 연동은 단순히 "기술적 구현"을 넘어 비즈니스 효율성을 크게 높인다. 매번 수동으로 관리하던 데이터를 자동화하면, 그 시간을 더 중요한 일에 쓸 수 있다. 이 글의 "서비스 계정 생성" 부분부터 차근차근 따라가면, 오늘 안에 구글 시트를 PHP 프로젝트에 연동할 수 있을 것이다. 특히 "실전 예제" 섹션의 클래스를 참고해 자신의 프로젝트에 맞게 수정해서 사용하면, 안정적이고 관리하기 쉬운 데이터 동기화 시스템을 만들 수 있다.