PHP / SQL Server / Ubuntu 18.04에서 연결하는 방법

Ubuntu 18.04의 PHP에서 SQL Server에 연결하려면 Microsoft ODBC 드라이버와 PHP용 sqlsrv 또는 pdo_sqlsrv 확장이 필요합니다. 다만 최신 PHP 드라이버를 무조건 설치하면 안 됩니다. 아래는 PHP 8.2가 이미 준비된 Ubuntu 18.04 x64 환경에서 5.11 계열 드라이버를 맞춰 연결하는 유지보수 절차이며, 새 서버는 지원 중인 OS·PHP 조합으로 구성하는 편이 적절합니다.

적용 범위와 버전 조합 먼저 확인

Ubuntu 18.04의 표준 보안 지원은 2023년에 끝났습니다. 계속 사용하는 시스템은 Ubuntu Pro의 확장 보안 유지관리(ESM) 적용 범위와 실제 활성 상태를 확인해야 합니다. Ubuntu ESM 안내를 참고하세요. OS의 보안 유지관리와 Microsoft PHP 드라이버의 호환·지원은 서로 다른 조건입니다.

Microsoft 호환표는 Ubuntu 18.04와 PHP 드라이버 5.11 조합을 열거하고, 5.11은 PHP 8.0·8.1·8.2를 지원합니다. 5.12에서는 Ubuntu 18.04 지원이 제거되었으므로 버전 없는 pecl install 명령으로 최신판을 가져오면 이 글의 전제와 달라집니다. Microsoft PHP 드라이버 호환표와 릴리스 변경 사항을 함께 확인합니다.

아래 명령은 2026년 10월의 유지보수 조건을 설명하기 위해 PHP 8.2와 sqlsrv·pdo_sqlsrv 5.11.1을 지정했습니다. PHP 8.2 자체의 보안 지원 기간도 PHP 지원 버전 표에서 확인하세요. 호환표에 있다는 이유만으로 앞으로 모든 OS·PHP 패치와 보안 요구를 만족한다고 보장할 수는 없습니다.

PHP 8.2·Apache 또는 PHP-FPM이 이미 해당 서버의 관리 가능한 패키지 경로로 설치되어 있어야 합니다. Ubuntu 18.04의 기본 PHP 7.2에 이 명령을 그대로 적용하지 마세요. 8.2 개발 패키지를 제공하는 신뢰할 수 있는 관리 경로가 없다면 지원되는 OS로 이전하는 작업이 먼저입니다. 지원되지 않는 저장소를 추가하거나 패키지 서명 검증을 끄는 방식으로 진행하지 않습니다.

cat /etc/os-release
uname -m
php -v
php --ini
phpize --version
php-config --version
pecl version

OS가 18.04인지, 아키텍처가 x86_64인지 확인하고 php·phpize·php-config·PECL이 모두 대상 PHP 8.2를 사용하는지 비교합니다. 다르면 빌드 대상과 실행 대상이 엇갈릴 수 있으므로 먼저 정리해야 합니다. 웹 요청의 PHP 버전과 설정은 CLI와 별도로 확인하며 phpversion() 사용법을 활용할 수 있습니다.

ODBC와 PHP 확장 설치

SQL Server는 같은 Ubuntu에 설치되어 있을 필요가 없습니다. 접속 가능한 서버 주소·TCP 포트, 데이터베이스와 애플리케이션 계정, 서버 인증서를 검증할 신뢰 경로를 준비합니다. 이 절은 SQL Server 엔진이나 계정을 만드는 절차가 아닙니다.

Microsoft 공식 Ubuntu 18.04 저장소 설정 패키지를 사용합니다. 이미 같은 저장소가 설정되어 있다면 중복 등록하지 말고 현재 설정을 먼저 확인하세요. 다음 ACCEPT_EULA=Y는 라이선스 동의를 뜻하므로 약관을 검토하고 동의한 경우에만 실행합니다.

curl -fsSLo packages-microsoft-prod.deb https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install msodbcsql17 unixodbc-dev
odbcinst -q -d

odbcinst 목록에서 ODBC Driver 17 for SQL Server가 보여야 합니다. 5.11.1 패키지는 ODBC 17.4.2 이상을 요구합니다. ODBC 공식 설치 안내의 Driver 17 절과 sqlsrv 5.11.1 요구 사항을 비교하세요. 설치 후보가 없거나 의존성이 맞지 않으면 다른 Ubuntu 버전의 저장소로 바꾸어 강행하지 않습니다.

sudo apt-get install build-essential php-pear php8.2-dev php8.2-xml
sudo pecl install sqlsrv-5.11.1
sudo pecl install pdo_sqlsrv-5.11.1

개발 패키지는 현재 실행할 PHP와 같은 버전이어야 합니다. PECL이 다른 phpize나 PHP API 대상으로 빌드했다면 성공 문구가 나와도 웹에서 로드되지 않을 수 있습니다. sqlsrv는 절차형 API, pdo_sqlsrv는 PDO용 확장이며 필요한 인터페이스만 사용할 수도 있습니다. 이 글의 연결 예제는 sqlsrv를 사용합니다.

현재 Microsoft의 새 환경 안내에는 PIE 설치 방식도 있지만, 여기서는 검증한 과거 버전 5.11.1을 지정하는 절차를 구분했습니다. 최신 설치법과 요구 사항은 Linux용 PHP 드라이버 설치 안내에서 확인하고, 이 Ubuntu 18.04 절차에 최신 버전을 섞지 마세요.

대상 SAPI에 확장을 로드하고 재시작

Debian·Ubuntu 방식의 PHP 8.2 패키지 구성을 전제로 /etc/php/8.2/mods-available/sqlsrv.ini와 pdo_sqlsrv.ini를 만듭니다. 기존 파일이 있으면 먼저 백업·비교하고 중복 로드 설정을 추가하지 않습니다. sqlsrv.ini 내용은 다음과 같습니다.

; priority=20
extension=sqlsrv.so

pdo_sqlsrv.ini는 다음과 같습니다. PDO 확장은 pdo_sqlsrv보다 먼저 로드되어야 합니다.

; priority=30
extension=pdo_sqlsrv.so
sudo phpenmod -v 8.2 -s cli sqlsrv pdo_sqlsrv
php8.2 --ri sqlsrv
php8.2 --ri pdo_sqlsrv

두 --ri 명령에서 대상 확장의 정보가 표시되는지 확인합니다. Module already loaded는 중복 설정, undefined symbol이나 PHP API 번호 오류는 빌드·실행 버전 불일치일 수 있습니다. 실제 확장 경로와 로딩 순서는 Microsoft 확장 로딩 문서를 참고하세요. 아래 두 방식 중 현재 서버에 맞는 한 가지만 적용합니다.

Apache 모듈 방식

Apache가 PHP 8.2 모듈을 직접 실행하는 경우입니다. 설정 검사를 통과한 뒤 작업 시간을 정해 Apache를 재시작합니다.

sudo phpenmod -v 8.2 -s apache2 sqlsrv pdo_sqlsrv
sudo apache2ctl configtest
sudo systemctl restart apache2

PHP-FPM 방식

Apache나 nginx가 PHP-FPM으로 전달하는 구성에서는 FPM용 설정을 활성화하고 해당 FPM 서비스를 재시작합니다. CLI 설정만 바꾸거나 다른 버전의 FPM을 재시작해도 현재 웹 요청에는 반영되지 않습니다.

sudo phpenmod -v 8.2 -s fpm sqlsrv pdo_sqlsrv
sudo systemctl restart php8.2-fpm

연결과 읽기 전용 쿼리 확인

제한된 테스트 위치에 sqlserver-config.php와 public/sqlserver-check.php를 준비합니다. 웹 루트는 public이고 설정 파일은 그 밖에 둡니다. 다음 설정의 예시 도메인·포트·계정·비밀번호를 실제 값으로 바꾸고 공개하거나 버전 관리에 넣지 않습니다.

<?php
return [
    'server' => 'tcp:db.example.test,1433',
    'database' => 'your_database',
    'username' => 'your_application_user',
    'password' => 'REPLACE_WITH_YOUR_PRIVATE_PASSWORD',
];

public/sqlserver-check.php의 전체 내용은 다음과 같습니다. 파일과 웹 응답은 UTF-8을 사용합니다. SQL Server가 제시하는 인증서의 이름과 접속 호스트가 일치하고 인증서 체인이 신뢰되어야 합니다.

<?php
header('Content-Type: text/plain; charset=UTF-8');
if (!function_exists('sqlsrv_connect')) {
    http_response_code(500);
    exit('현재 PHP에 sqlsrv 확장이 로드되지 않았습니다.');
}
function failSql($stage, $errors): void {
    $codes = [];
    foreach ($errors ?? [] as $error) {
        $codes[] = ['SQLSTATE' => $error['SQLSTATE'], 'code' => $error['code']];
    }
    error_log($stage . ': ' . json_encode($codes));
    http_response_code(500);
    exit('SQL Server 확인에 실패했습니다. 서버 로그를 확인하세요.');
}
$c = require dirname(__DIR__) . '/sqlserver-config.php';
$conn = sqlsrv_connect($c['server'], [
    'Database' => $c['database'], 'UID' => $c['username'], 'PWD' => $c['password'],
    'Driver' => 'ODBC Driver 17 for SQL Server',
    'CharacterSet' => 'UTF-8', 'LoginTimeout' => 5,
    'Encrypt' => true, 'TrustServerCertificate' => false,
    'ConnectionPooling' => false,
]);
if ($conn === false) failSql('connect', sqlsrv_errors());
$stmt = sqlsrv_query($conn, "SELECT 1 AS connected, N'연결 확인' AS message");
if ($stmt === false) {
    $errors = sqlsrv_errors();
    sqlsrv_close($conn);
    failSql('query', $errors);
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
$errors = sqlsrv_errors();
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
if (!is_array($row)) failSql('fetch', $errors);
echo $row['message'], ': ', $row['connected'], PHP_EOL;

PHP가 실행되는 웹 경로로 이 파일에 접근했을 때 연결 확인: 1이 표시되면 접속·쿼리·결과 읽기가 완료된 것입니다. 진단 파일의 공개 접근을 제한하고 확인 후에는 정리하세요. 쿼리는 상수 한 행만 읽으므로 테이블 데이터는 변경하지 않습니다.

예제는 Encrypt를 true, TrustServerCertificate를 false로 지정합니다. 인증서 오류를 해결하기 위해 검증을 끄기보다 서버 인증서와 신뢰 체인을 맞춰야 합니다. 또한 구형 unixODBC와의 풀링 조건을 피하도록 이 진단 연결의 ConnectionPooling을 false로 지정했습니다. 연결 값의 의미는 SQLSRV 연결 옵션을 참고하세요.

sqlsrv_connect()와 쿼리는 실패 시 false를 반환할 수 있습니다. 결과 읽기는 행 배열·종료 null·실패 false를 구분해야 합니다. 본문에 전체 서버 오류를 출력하지 않고 로그에는 단계와 SQLSTATE·코드만 남겼습니다. 운영에서는 PHP의 상세 오류 출력과 로그 접근 권한도 관리해야 합니다.

연결되지 않을 때 계층별 점검

증상 확인할 항목
sqlsrv_connect가 없음 현재 웹 SAPI의 PHP 버전, 확장 로딩 설정과 재시작 대상을 확인합니다.
ODBC 드라이버를 찾지 못함 odbcinst 목록, 드라이버 설치·라이브러리 의존성을 확인합니다.
연결 시간 초과 서버 DNS·TCP 포트, SQL Server 수신 설정과 접근 허용 범위를 확인합니다.
로그인 실패 SQL 인증 설정, 계정·비밀번호와 데이터베이스 접근 권한을 확인합니다.
인증서 검증 실패 접속 이름, 인증서 유효성·신뢰 체인과 클라이언트 신뢰 저장소를 확인합니다.
CLI에서는 되고 웹에서는 안 됨 PHP 실행 파일·SAPI·추가 ini 파일과 서비스 사용자 차이를 확인합니다.

기존 설정으로 되돌려야 한다면 변경한 ini와 서비스 구성을 백업과 비교해 복원한 뒤 해당 실행 환경을 재시작하고 확인합니다. 공유 서버의 다른 PHP 버전이나 저장소를 함께 제거하지 마세요. 최신 지원 조합으로 이전할 때도 OS·PHP·PHP 드라이버·ODBC·SQL Server를 각각 확인해야 하며, Ubuntu 버전 하나만 바꾸는 것으로 호환 검토가 끝나지는 않습니다.