파일에서 텍스트를 읽거나 파일에 저장을 할 수 있게 되면, 꽤 할 수 있는 것이 많아 진다. 텍스트 파일의 기본적인 사용에 대해 설명한다.


readfile을 이용한 텍스트 파일 로드

텍스트 파일의 내용을 읽어 표시하는 것은 PHP에서는 놀라울 정도로 간단하다. 그대로 "지정된 텍스트 파일을 로드하고 표시한다"는 것을 해주는 함수가 준비되어 있다.

실제로 해보자. 먼저 텍스트 파일을 준비한다. 실행하는 PHP 파일 (여기에서는 index.php)와 같은 위치에 "data.txt"라는 텍스트 파일을 생성하고, 그 안에 적당히 텍스트를 써 넣는다. 이것은 PHP와 마찬가지로 UTF-8 인코딩으로 저장한다. 인코딩이 다르면 문자가 깨진다.

파일이 준비 되면, 스크립트를 만들자. index.php에 아래와 같이 소스 코드를 작성한다.

<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type"
            content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <p><?php readfile("data.txt"); ?></p>
    </body>
</html>

그리고 페이지를 접속해 보면, 텍스트 파일의 내용이 그대로 표시될 것이다.

여기에서 사용하고 있는 PHP 스크립트는 바디(body) 부분에 써 있는 단 한 줄의 함수뿐이다. 해당 함수 부분은 아래와 같다.

<?php readfile("data.txt"); ?>

이 "readfile"라고 하는 것이 ()에 지정된 파일을 읽어 들여 그 자리에 내보내는 함수이다. 텍스트를 표시할 위치에 이 함수를 써두는 것만으로 거기에 파일의 내용이 출력된다. echo로 출력할 필요도 없다. 단지, readfile 함수만 있으면 된다.

그러나 실제로 해보면 이것으로는 여러가지 부족함이 있을 것이다. 먼저 여러 줄의 텍스트가 써있어도 줄 바꿈되지 않고 표시된다. HTML에서 <br> 태그을 사용하여 줄 바꿈을 해주지 않으면 안되기 때문이다. readfile은 줄 바꿈을 자동으로 <br>로 변환해 주거나 하지 않는다.

또한, 꺼낸 텍스트를 그대로 써 넣기 때문에 부분적으로 뭔가 처리를 하고 싶은 경우에는 이를 사용할 수 없다. 어디 까지나 내용을 통째로 거기에 단순히 꺼낼 뿐이다.


file를 사용한 파일의 텍스트를 한줄씩 처리

그럼 읽어온 텍스트를 처리하기 위해서는 어떻게 해야 하는 걸까. 여기에는 "파일의 내용을 통째로 읽어 들여, 한줄씩 배열에 정리해 돌려주는" 함수가 준비되어 있기 때문에 이를 이용하면 된다. 이것은 "file"이라는 함수이다.

$변수 = file(파일 지정);

이렇게 하면 인수에 지정된 파일을 읽어 들여, 한줄씩 나누어 정리한 배열을 돌려준다. 이후에는 "$변수"에서 배열의 요소를 차례로 꺼내 처리해 가면 된다.

그러나 일반적으로 이렇게 간단한 작성을 하는 경우는 별로 없다. 왜냐하면 이것만으로는 "파일 로드에 실패할 경우"를 처리할 수 없기 때문이다. 만약 파일로드에 실패하면 그 시점에서 오류가 발생하여 스크립트의 실행을 중단해 버린다. 그렇게 되면 그 이후의 처리 및 표시도 되지 않고 페이지가 도중에 잘려 버린다.

그래서 file과 같이 실행에 실패할 가능성이 있는 경우

$변수 = @file(파일 지정) or 실패 처리;

이런 식으로 쓰는 것이 일반적이다. 함수명 앞에 '@'기호를 붙이면 실행에 실패해도 스크립트를 중단하지 않고 계속 진행을 하게 된다. 또한 함수 뒤에 "or"를 붙이면 실행에 실패했을 때 or 이후의 처리를 수행할 수 있다.

그러면 아래에 간단한 예제를 보도록 하자.

<?php
    $result = "";
    $lines = @file("data.txt") or $result = "파일을 읽을 수 없습니다.";
    if ($lines != null){
        for($i = 0;$i < count($lines);$i++){
            $result .= ($i + 1) . ": " . $lines[$i] . "<br>";
        }
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type"
            content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <p><?php echo $result; ?></p>
    </body>
</html>

이는 data.txt를 읽어 들여, 1행씩 행번호를 붙여 표시한다. 물론 각 행도 제대로 줄 바꿈되어 표시된다. 여기에서는

$lines = @file("data.txt") or $result = "파일을 읽을 수 없습니다.";

이렇게 하여 파일을 로드하고 있다. 그리고 읽어온 $lines 배열을 비울 때까지 반복하고 있다. 비었는지에 대한 여부는

if ($ lines! = null) {......

이렇게 체크를 하고 있다. "null"이라는 것은 "빈" 것을 나타내는 예약어이다. 변수에 값이 설정되지 않은 (즉, 빈) 상태를 나타내는 말이다.

무사히 가져온다면, for($i = 0; $i <count($lines); $i++) 이렇게 하여 $lines에서 한줄씩 텍스트를 읽어 와서 처리를 하고 있다. count($lines)이라고 하는 것은, $lines 요소의 수를 지정하는 것이다. "count"라는 것은 인수에 지정된 배열의 요소 수를 반환하는 함수이다.


텍스트를 분할하여 처리(explode, implode)

텍스트 파일은 다양한 데이터를 처리하는데 사용된다. 예를 들어, Excel 시트처럼 화면에 가로로 늘어 놓는 데이터를 작성하는 데에도 이용된다.

이러한 "많은 데이터가 작성된 텍스트"를 사용하는 방법을 알면, 텍스트 파일을 사용하여 간단한 데이터베이스적인 사용이 가능하게 된다.

그럼 실제로 해보자. 먼저 샘플 data.txt 텍스트 파일의 내용을 다음과 같이 내용을 변경한다.

원석, won@flower.ko, 010-9999-9999
성진, sung@yamada.jp, 010-8888-8888
병호, byeong@baseball.com, 010-7777-7777

여기에서는 개인 정보(이름, 이메일 주소, 전화 번호)를 쉼표로 구분해서 한줄씩 줄바꿈하여 데이터를 기술되어 있다. 이렇게 하면 한줄씩 데이터를 검색하여 거기에서 각 항목의 값을 꺼내 처리할 수 있을 것 같다.

이것을 읽어 표시하는 예제를 보도록 하자.

<?php
    $lines = @file("data.txt") or $result = "파일을 읽을 수 없습니다.";
    if ($lines != null) {
        $result = '<table border="1">';
        $result .= "<tr><th>NAME</th><th>MAIL</th><th>TEL</th></tr>";
        for($i = 0; $i < count($lines); $i++){
            $result .= "<tr>";
            $arr = explode(",", $lines[$i]);
            for($j = 0;$j < 3;$j++){
                $result .= "<td>{$arr[$j]}</td>";
            }
            $result .= "</tr>";
        }
        $result .= "</table>";
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <p><?php echo $result; ?></p>
    </body>
</html>

액세스하면 데이터가 테이블을 사용한 테이블의 형태로 나타난다.

여기에서 file에서 텍스트를 각 행마다 배열로 얻어내어, for의 반복 처리를 하고 있다. 얻어온 행 텍스트는 쉼표 기호로 3개의 텍스트로 분할되어 처리된다. 여기에서는

$arr = explode(",", $lines[$i]);

이것이 $lines[$i]의 텍스트를 쉼표로 분리하고 있는 부분이다. "explode"라고 하는 것은, 첫번째 인수로 지정한 문자를 사용하여 두 번째 인수의 텍스트를 분할하고 배열에 정리해 반환하는 함수이다. 여기에서는 쉼표(,)를 첫번째 인수로 지정하고 있다. 그러면, 두번째 인수의 텍스트를 쉼표로 분리하고 있다. 분할 된 배열의 텍스트에서 쉼표은 사라진다. 즉, explode로 분할하면 단락 문자는 없게 되므로 주의하자.

이와 반대로 배열에 정리한 텍스트를 지정된 구분 기호를 사용하여 하나의 텍스트로 정리할 수도 있다.

$변수 = implode(구분 문자, 배열);

이 "implode"함수를 사용하면 배열의 각 요소의 텍스트를 구분 기호 사이에 두고 하나의 텍스트로 정리한다. 즉, explode으로 분해한 배열을 바탕으로 되돌릴 수 있다는 것이다. 세트로 기억하도록 하자.



fopen 통한 파일 액세스

file()를 이용한 파일의 읽기보다도 더 유연한 대응이 필요한 경우에는, PHP에서 제공되는 가장 기본적인 파일 액세스 함수를 조합하여 사용할 수 있다. 이는 3단계의 절차로 파일에 액세스할 수 있다.

1. 파일 열기

$변수 = fopen(파일 지정, 모드 지정);

먼저 'fopen'라는 함수를 호출한다. 이는 인수에 지정된 파일을 열고 그 파일에 액세스할 수 있는 "파일 포인터"라는 것을 돌려준다. 파일에 액세스하는 경우는 반드시 이 fopen으로 파일을 연다.

두번째 인수에 있는 "모드 지정"이라는 것이 fopen의 포인트이다. 이는 해당 파일의 액세스 형태라는 것을 지정한다. 액세스 모드는 그 파일을 "어떤 종류의 파일를 처리할지", "어떤 접근을 허용할지"에 대한 설정을 할 것이다. 이 모드는 다음과 같은 기호를 사용하여 지정한다.

fopen 모드를 지정하는 기호

인자모드포인터 위치파일이 존재 유무
r읽기 전용파일의 시작파일 내용 보존
r+읽고 쓰기파일의 시작파일 내용 보존
w쓰기 전용파일의 시작파일 내용 삭제, 없으면 새로 생성
w+읽고 쓰기파일의 시작파일 내용 삭제, 없으면 새로 생성
a쓰기 전용파일의 끝파일 내용 보존, 없으면 새로 생성
a+읽고 쓰기파일의 끝파일 내용 보존, 없으면 새로 생성
x쓰기 전용새로운 파일 생성파일이 존재하면 false 리턴 그리고 에러 남
x+읽고 쓰기새로운 파일 생성파일이 존재하면 false 리턴 그리고 에러 남
  • 위의 모드 인자뒤에 마지막에 b나 t를 붙일 수 있다.
    • b : 바이너리 모드로 열기
    • t : 텍스트 파일의 라인 변경 태그를 Unix에서는 \n를 사용하고, 맥에서는 \r만 사용하는데 윈도우에서는 \r\n를 사용하는데, 이러한 \n을 \r\n으로 변환해준다. 따라서 다른 시스템의 텍스트 파일을 윈도우 플랫폼에서 열 때 사용하면 좋다.

2. 데이터에 액세스하기

파일을 열리면, 그 다음에 하는 작업은 그 파일에서 필요한 데이터를 읽거나 데이터를 쓰거나 하는 작업을 실행한다. 여기에는 "fgets", "fputs"라는 함수가 준비되어 있다. (각각에 대해서는 나중에 설명하겠다)

3. 파일 닫기

fclose(파일 포인터);

데이터 액세스가 완료되면 마지막으로 파일을 닫는다. 이는 "fclose"라는 함수로 실행한다. 인수는 fopen으로 얻어진 파일 포인터를 지정한다.

왜 fopen에서 파일을 열고 fclose으로 닫는 작업을 하지 않으면 안 되는가? 그것은 이것에 의해 파일 액세스 권한이 설정되기 때문이다. 일반적으로 컴퓨터의 응용 프로그램 등으로 파일을 사용하는 경우, 어느 응용 프로그램이 사용 중이라고 다른 파일로 열 수 없거나, 파일 삭제 등을 할 수 없게 된다. 그것은 "이 응용 프로그램을 사용 중이다"라는 것을 표시해주고 다른 프로그램에서 액세스할 수 없도록 하고 있기 때문이다.

만약 여러 프로그램에서 동시에 파일 액세스할 수 된다며, 그 내용이 생각하지 못한 형태로 재작성되어 버릴 가능성이 있다. 그래서 파일에 쓰여진 데이터가 손상되지 않도록 "파일을 사용할 수 있는 것은 한번에 하나의 애플리케이션만 가능"하도록 되어 있다.

fopen 및 fclose도 이와 같은 일을 하고 있는 것이다. fopen으로 파일을 열면 다른 프로그램이 마음대로이 파일을 열어서 내용을 다시 작성할 수 없게 된다. 그리고 모든 작업 후에 fclose을 실행하여 파일을 닫아 개방하여 다른 프로그램이 파일을 사용할 수 있게 한다.



fgets를 사용하여 파일 로드

먼저 fopen을 사용한 "파일 읽기"부터 보도록 하자. 여기에서는 data.txt의 내용을 fopen 이용해서 읽어서 표시해 보려고 한다. 뭐, 해려고 하는 것은 지금까지와 변함 없지만 ...

아래에 예제 코드를 보도록 하자.

<?php
    $f = @fopen("data.txt",'r') or exit("BREAK");
    $result = '';
    while(!feof($f)){
        $result .= fgets($f,10);
    }
    fclose($f);
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <p><?php echo $result; ?></p>
    </body>
</html>

fopen으로 파일을 열고, fclose으로 닫는 것은 이 전에 설명한대로 이다. fopen에서 예제로 "오류시 처리"도 하고 있다. 여기에서 "exit"라는 것이 사용되고 있는데, 이것은 "처리 종료"위한 것이다. 즉, 여기서 조작을 중단하고 인수의 텍스트인 "BREAK"를 화면에 출력하고 끝낸다.

파일의 데이터를 읽는 처리는 "fgets"라는 함수를 사용한다. 이것은

$변수 = fgets(파일 포인터);
$변수 = fgets(파일 포인터, 바이트수);

이런 식으로 호출한다. 인수에는 읽을 파일 포인터를 지정한다. 두번째 인수가 없으면 한줄만 읽어 드린다. 두번째 인수에 정수를 지정하면 해당 바이트 수 만큼 읽는다.

이 fgets는 "로드 위치"의 정보를 보존하고 있다. 어느 파일에서 100 바이트를 로드하면 그 만큼의 데이터를 읽어 들여, 그 자리에 "로드 위치"를 이동시키는 것이다. 또한 fgets를 호출하면 100 바이트씩 이동한 로드 위치에서 다시 계속 읽어들인다. 이렇게 fgets를 여러번 호출하여, 대용량 파일도 시작 부분부터 조금씩 읽어 나가는 수 있다.

또한 파일을 로드 할 시에 "어디서 파일이 마지막이 될지"도 체크하지 않으면 안된다. 이것은 "feof"라는 함수를 사용한다. 인수에 파일 포인터를 설정해서 호출하면 파일의 로드 위치가 파일의 끝까지 닿아 있으면 true, 아직 남아 있다면 false를 반환한다. 예제 코드를 보면,

while(!feof($f)){......

이런 식으로 반복을 하고 있다. 변수 이름 앞에 있는 "!"는 "부정"의 기호이다. 부울값(true / false)이 true이면 false, false이면 true와 같이 반대 값을 반환 연산자이다. 이것으로 feof($f)이 false인 동안 (즉, 아직 남아있다)에 반복을 계속하도록 하는 것이다.



fputs를 사용하여 파일 저장

그럼 이제 파일을 저장해 보자. 이것은 "fputs"라는 함수를 사용한다. 다음과 같은 형태로 호출한다.

fputs (파일 포인터, 데이터);

단지 이것만으로 파일에 데이터를 저장할 수 있다. 파일로 쓰기를 할 때에 주의해야 할 점은 액세스 모드이다. 쓰기 액세스 모드는 2종류이기 때문에 실수하지 말길 바란다.

'w'를 지정한 경우는 "덮어 쓰기 모드"이다. 이미 파일이 있을 경우, 이를 지우고 새로운 파일을 만들어 fputs에 쓴다.

'a'를 지정한 경우는 "추가 쓰기 모드"이다. 이미 파일이 있다면, 그 파일의 마지막에 fputs한 내용을 추가한다. 즉, fputs으로 점점 데이터를 추가하는 것이다.

용도에 따라, 이 두가지 모드를 구사할 수 있도록 하자. 그럼 아래에 간단한 예제를 보도록 하자.

<?php
    // 데이터 추가
    if ($_POST != null){
        $f = @fopen("data.txt",'a') or exit("파일을 읽을 수 없습니다.");
        if ($f != null){
            $s = $_POST['text1'];
            fputs($f,$s . "\n");
            fclose($f);
        }
    }
    // 파일 읽기
    $f2 = @fopen("data.txt",'r') or exit("파일을 읽을 수 없습니다.");
    $result = '';
    $i = 1;
    while(!feof($f2)){
        $s2 = htmlspecialchars(fgets($f2));
        if ($s2 != ""){
            $result = $i++ . ": " .$s2 . "<br>" . $result;
        }
    }
    fclose($f2);
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <form method="post" action="./index.php">
            <input type="text" name="text1">
            <input type="submit">
        </form>
        <hr>
        <p><?php echo $result; ?></p>
    </body>
</html>

이것은 간단한 메모를 쓸 수 있는 어플리케이션이다. 입력 필드에서 텍스트를 써 보내면, 그 내용이 파일에 추가가 된다. 입력 양식의 아래에 저장된 메모가 새로운 것부터 순서대로 번호를 부여하여 표시된다.

여기에서는 "파일 저장", "파일 가져 오기"를 모두 사용하고 있다. 어떻게 움직이고 있는지 각자 자세히 보도록 하자. 파일 액세스를 할 수 있게 되면 이런 식으로 좀 더 실용적인 것을 서서히 만들 수 있게 될 거다.

Linux 혹은 Mac OS 환경에서 파일 권한 오류

혹시 Linux 혹은 Mac OS에서 파일에 추가가 되지 않는다면 파일의 쓰기 권한이 있는지 확인 해보자. 만약에 없다면 아래와 같이 명령어로 쓰기 권한을 주면 된다.

$ chmod 666 data.txt 
  • 파일 권한에 대한 자세한 내용은 리눅스 명령어에 대해 찾아보길 바란다.



인터넷 상에 파일도 읽을 수 있다(?)

지금까지 PHP 파일 액세스 함수에 대해 간략히 정리해 왔지만, 마지막에 중대한 비밀(?)을 알려 주겠다.

사실 PHP 파일 관련 함수는 로컬 볼륨에 저장되어 있는 파일뿐 아니라, 인터넷에 있는 파일도 동일하게 액세스할 수 있다!

단, 파일의 쓰기 변경은 할 수 없다. 기본적으로 데이터를 읽을 수 있을 뿐이다. 그래도 여전히 "Web 사이트의 데이터를 자유롭게 읽을 수 있다"라면, 이것은 대단하다고 생각되지 않는가?

사용법은 간단하다. 각각의 함수로 파일을 지정할 인수에 파일 이름이나 파일 경로 대신에 URL을 적으면 된다. 예를 들어,

$lines = file("http://www.google.com/");

이런 식으로 하면 Google의 톱 페이지의 HTML 코드가 모두를 가져올 수 있다.

아래에 실제 간단한 사용 예를 보도록 하자.

<?php
    if ($_POST != null){
        $url = $_POST['text1'];
        $lines = file($url);
        $result = implode($lines);
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <form method="post" action="./index.php">
            <input type="text" name="text1" size="40"
                value="<?php echo htmlspecialchars($url); ?>"><br>
            <input type="submit">
        </form>
        <hr>
        <?php echo htmlspecialchars($result); ?>
    </body>
</html>

입력 필드에 URL을 써서 송신하면, 그 페이지의 내용을 다운로드하고 아래로 쓰기를 한다. 실제로 해보자. 간단히 다른 사이트의 데이터를 꺼낼 올 수 있다는 것을 알 수 있다.

어쨌든 네트워크에 있는 파일을 로드할 때에는 로드에 실패하거나 매우 시간이 걸리거나 하는 것도 많기 때문에, 그러한 경우의 대응도 생각해 두지 않으면 안된다. 아무튼 이렇게 쉽게 Web 데이터를 꺼낼 얻어 올 수 있다면 여러가지에 응용할 수 있을 것이 있지 않을까 싶다.


'php' 카테고리의 다른 글

[php] 페이지 전환, 쿠키, 세션  (0) 2017.12.09
[php] 텍스트 및 날짜 조작  (0) 2017.12.09
[php] 텍스트 파일 이용  (1) 2017.12.09
[php] form 전송 기본  (0) 2017.12.09
[php] 제어 구문  (0) 2017.12.09
[php] 산술 연산자  (0) 2017.12.09
  1. 메롱!_! 2019.01.25 20:47 신고

    안녕하세요

+ Recent posts