PHP FileManager 파일매니저



웹 애플리케이션을 개발하고 관리하다 보면 서버 내의 특정 경로에 폴더를 생성하거나, 텍스트 기반의 환경 설정 파일을 읽고 쓰고, 때로는 중요한 원본 데이터를 백업하거나 이동시켜야 하는 파일 시스템 제어 작업을 끊임없이 마주하게 됩니다.

PHP는 강력한 기본 파일 입출력 함수들을 제공하지만, 매번 경로 검증, 상위 경로 이동 취약점 방어(Directory Traversal 예방), 파일 락킹(Locking), 백업 분기 처리 등을 일일이 코딩하는 것은 매우 번거롭고 보안상 허점을 남기기 쉽습니다.

이번 포스팅에서는 서버 내 파일 및 디렉토리 관련 다중 핵심 기능들을 안전하고 깔끔하게 캡슐화한 PHP 실무형 고급 FileManager 클래스 라이브러리 소스코드와 올바른 활용법을 정리해 드립니다. 아래 가이드 내용을 마우스로 드래그하여 가독성 높은 반전 효과를 직접 확인해 보세요!

🛡️ 웹 파일 매니저 아키텍처 핵심 보안/기능 팁:
- 디렉토리 탐색(Directory Traversal) 원천 차단: 파일 경로 검증 메서드인 fpath() 내부에 ../ 패턴을 강제로 공백("") 치환 처리하는 로직을 내장하여, 악의적인 사용자가 웹 루트 상위의 시스템 민감 폴더에 접근하는 해킹 공격을 구조적으로 예방합니다.
- 동시성 제어를 위한 파일 락킹: 파일을 생성하거나 갱신(fmake)할 때 flock($fp, LOCK_EX)를 적용하여, 동일한 순간에 트래픽이 몰려 여러 프로세스가 한 파일을 동시에 쓰면서 데이터가 깨지거나 손실되는 레이스 컨디션 버그를 원천 차단합니다.
- 안전한 파일 이동(Move): 단순히 시스템 명령어를 호출하는 대신 복사(Copy) 성공 여부를 철저하게 검증한 뒤 안전하게 원본을 제거(Unlink)하는 롤백 안전망 메커니즘이 빌드되어 있습니다.

1. PHP FileManager 클래스 및 라우팅 컨트롤러 전체 소스코드

프로젝트 모듈이나 Helper 컴포넌트로 즉시 등록하여 사용할 수 있도록 백엔드 파일 처리 코어 로직과 외부 파라미터 수신 및 Ajax/Text 응답 반환 로우 처리부까지 완벽하게 통합된 PHP 스크립트입니다.

<?php
class FileManager {

    // [메서드] 생성자
    public function __construct() {
    }

    // [메서드] 안전한 절대 파일 경로 추출 및 상위 경로 침투 방어 검증
    public function fpath($link = '') {
        $root = getenv('DOCUMENT_ROOT');
        $sp = substr($root, -1) == '/' ? '' : '/';
        $pattern = array('//', '../');
        $replace = array('/', '');
        return str_replace($pattern, $replace, $root . $sp . $link);
    }

    // [메서드] 일시 분 단위 기준 파일 자동 백업 생성
    public function fbackup($filelink) {
        $filelink = $this->fpath($filelink);
        $fileback = $filelink . '_' . date("YmdHi");
        if(file_exists($filelink)) {
            @copy($filelink, $fileback);
            @chmod($fileback, 0755);
        }
    }

    // [메서드] 파일 생성 및 수정 (배열 데이터 락킹 및 옵션 백업 지원)
    public function fmake($filelink, $buffer, $mode = 'w', $C = 0) {
        if(!$buffer) die();

        if($C == 1) {
            $this->fbackup($filelink); // 백업 옵션 활성화 시 선행 백업 실행
        } 
        
        $filelink = $this->fpath($filelink);
        $fp = fopen($filelink, 'w'); 
        if(flock($fp, LOCK_EX)) { // 베타적 락킹 획득
            fwrite($fp, $buffer); 
            flock($fp, LOCK_UN);  // 락킹 해제
            $response = true; 
        } else { 
            $response = false; 
        } 
        fclose($fp); 

        return $response; 
    }

    // [메서드] 안전한 라인별 스트림 파일 읽기 처리
    public function freads($filelink) {
        $filelink = $this->fpath($filelink);
        $fp = fopen($filelink, 'r');
        $response = '';
        while (!feof($fp)) {
            $response .= fgets($fp) . "\n";
        }
        fclose($fp); 

        return $response; 
    }

    // [메서드] 퍼미션 지정을 포함한 신규 디렉토리 생성
    public function fmkdir($filelink) {
        $filelink = $this->fpath($filelink);
        return @mkdir($filelink, 0777);
    }

    // [메서드] 빈 디렉토리 안전 삭제
    public function frmdir($filelink) {
        if (is_dir($filelink)) {
            return @rmdir($filelink); // 폴더 내 파일 잔존 시 false 반환
        }
    }

    // [메서드] 디렉토리 및 파일 범용 제거 처리
    public function fremove($filelink) {
        $filelink = $this->fpath($filelink);
        if (is_dir($filelink)) {
            return @rmdir($filelink);
        }
        if (file_exists($filelink)) {
            return @unlink($filelink);
        }
    }

    // [메서드] 파일 복사 처리 및 무결성 검증
    public function fcopy($filelink, $newlink) {
        $filelink = $this->fpath($filelink);
        $newlink = $this->fpath($newlink);
        if(file_exists($filelink)) {
            if(!copy($filelink, $newlink)) {
                return false;
            }
            return true;
        }
    }

    // [메서드] 트랜잭션형 안전 파일 이동 알고리즘
    public function fmove($filelink, $newlink) {
        $filelink = $this->fpath($filelink);
        $newlink = $this->fpath($newlink);
        if(file_exists($filelink)) {
            if(!copy($filelink, $newlink)) {
                return false; // 복사 실패 시 원본 원천 보존
            } else if(file_exists($newlink)) {
                // 복제 완료 타겟 실재 확인 후 안전하게 원본 격리 제거
                if(!@unlink($filelink)) {
                    if(@unlink($newlink)) {
                        return NULL; // 트랜잭션 롤백 처리 실패 시 예외 리턴
                    }
                }
            }
        }
        return true;
    }

    public function ftest($filelink, $f1, $f2, $f3) {
        $filelink = $this->fpath($filelink);
        echo 'TEST : ' . $filelink . ' | ' . $f1 . ' | ' . $f2 . ' | ' . $f3;
    }
}

// 1. 파일 매니저 컴포넌트 객체화 인스턴스 생성
$FileManager = new FileManager();

// 2. 외부 글로벌 라우팅 핸들러 매핑 바인딩 처리부
if (isset(Request()->m)) {
    $type = Request()->t;
    $method = Request()->m;
    $filelink = Request()->f;
    $f1 = Request()->f1;
    $f2 = Request()->f2; 
    $f3 = Request()->f3;
    
    // 가변 함수 기능을 이용한 요청 메서드 동적 라우팅 호출
    $response = $FileManager->{$method}($filelink, $f1, $f2, $f3);
}

// 3. API 클라이언트 타입별 최종 데이터 포맷팅 리턴 처리부
if (isset($response)) {
    if ($type == "ajax") {
        echo json_encode($response); // JSON 타입 아웃풋 반환
    } elseif ($type == "text") {
        echo $response;              // 일반 텍스트 포맷 아웃풋 반환
    } else {
        return $response;            // 시스템 백엔드 내부 객체 직접 반환
    }
}
?>

2. 핵심 컴포넌트 톺아보기 및 외부 호출 인터페이스

해당 스크립트 하단에는 외부에서 파라미터를 던져 가변 함수 구조($FileManager->{$method}(...))로 동적 라우팅을 수행하는 API 가 연결되어 있습니다. 예를 들어 프론트엔드 JavaScript나 외부 시스템에서 특정 파일을 읽어오거나 비동기 Ajax로 새 텍스트를 파일로 기록하고 싶다면 다음과 같이 파라미터를 매핑하여 요청할 수 있습니다.

  • ?m=freads&f=config/settings.txt&t=text : settings.txt 파일의 텍스트 내용을 고속으로 읽어와 화면에 스트링으로 출력합니다.
  • ?m=fmake&f=log.txt&f1=새로운로그버퍼데이터&f2=w&f3=1&t=ajax : 기존 log.txt를 일시 분 단위 타임스탬프로 안전하게 선행 백업(f3=1)한 뒤, 새 로그를 기록하고 결과 성공 유무(true/false)를 깨끗한 JSON 포맷으로 수신합니다.

3. PHP 시스템 파일 입출력 공식 레퍼런스 문서

본 클래스 라이브러리 내부에 매핑된 파일 시스템 함수군(fopen, flock, mkdir 등)의 세부 에러 제어 마스킹이나 리눅스/윈도우 서버 환경별 권한 설정(chmod 퍼미션)에 대한 공식 가이드는 아래 공식 PHP 개발자 매뉴얼 단추 링크를 통해 상세히 체크해 보실 수 있습니다.

4. 맺음말

안전성과 예외 처리가 검증되지 않은 순수 입출력 코드를 무분별하게 웹 프로젝트 전반에 흩어놓으면 동시성 데이터 깨짐 현상이나 원격 파일 인클루드 같은 심각한 웹 취약점에 노출될 우려가 큽니다. 오늘 소개해 드린 캡슐화된 FileManager 모듈 헬퍼 클래스를 공통 라이브러리에 내장하여 웹 서버 인프라 자원을 안전하고 정교하게 제어해 보시기 바랍니다!