[PHP] IO 사용법


Study/PHP  2019. 9. 19. 09:00

안녕하세요. 명월입니다.


이 글은 PHP에서 사용하는 IO에 관한 글입니다.


I/O는 Input/Output의 의미입니다만, 프로그램에서 I/O라고하면 파일 입출력을 뜻하는 말입니다.

프로그램을 작성하다보면 Property로써 파일을 읽어드릴 때도 있고, 클라이언트(브라우저)로 데이터를 보내기 위해 읽는 경우도 있습니다.

반대로 프로그램 상에서 꼭 데이터 베이스에 입력하는 것이 아닌 파일로써 데이터를 보존해야하는 경우도 있습니다.


그런 상황에서 사용되는 I/O기능입니다.

<?php
  $contents = "";
  try{
    // 파일이 있는 경우는 if의 안으로 들어가고 없는 경우는 fopen을 실행하지 않는다
    if(@$handle = fopen('data.txt', 'r')) {
      $contents = fread($handle, filesize('data.txt'));
    }
  } catch(Exception $e){
    print_r($e);
  } finally{
    // I/O 리소스는 반드시 close를 해야한다.
    @fclose($handle);
  }
?>
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
  <?=$contents?>
</body>
</html>

그리고 같은 폴더의 data.txt파일을 만들어서 읽어 드립니다.

여기서 data.txt에서는 개행이 있는데 웹페이지에서는 한 줄로 표시가 되네요. 이는 웹 페이지에서 개행은 <br />태그를 이용해야 개행이 이루어지기 때문입니다.

그리고 I/O의 경우는 사용후에 반드시 close를 해야합니다. 그렇지 않을 경우, 프로그램 상에서 I/O리소스를 계속 사용 중이 되기 때문에 다른 세션에서 사용할 수 없어지기 때문입니다.

PHP내에서 response가 끝나면 자동으로 리소스를 자동으로 반환 시켜주기는 하지만, 프로그램의 성능을 위해 사용이 끝나면 바로바로 리소스를 반환해야 합니다.


이번에는 페이지에서 넘어오는 post값을 file로 작성해 보겠습니다.

<?php
  $data = "";
  if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $data = $_POST["data"];
    try {
      // 파일이 있는 경우는 if의 안으로 들어가고 없는 경우는 fopen을 실행하지 않는다
      if (@$handle = fopen('data.txt', 'a')) {
        fwrite($handle, $data . "\r\n");
      }
    } catch (Exception $e) {
      print_r($e);
    } finally{
      // I/O 리소스는 반드시 close를 해야한다.
      @fclose($handle);
    }
  }
?>
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
  <form method="POST">
    <input type="text" name="data" value="<?=$data?>"> 
    <input type="submit">
  </form>
</body>
</html>

처음 파일을 읽을 때는 fopen을 이용해서 파라미터를 r를 넣었습니다. 그리고 fread로 파일을 읽어왔습니다.

다시 파일을 쓸때는 a라는 파라미터를 넣어서 파일을 읽었습니다.

모드 설명
r 읽기 전용 모드입니다. 이때 포인트는 맨 앞입니다.
r+ 읽기 + 쓰기 모드입니다. 이때 포인트는 맨 앞입니다.
w 쓰기 전용입니다. 파일은 초기화됩니다. 파일이 존재하지 않으면 작성됩니다.
w+ 쓰기 + 읽기입니다. 파일이 초기화됩니다. 파일이 존재하지 않으면 작성됩니다.
a 쓰기 전용입니다. 포인트는 맨 뒤입니다.
a+ 쓰기 + 읽기입니다. 포인트는 맨 뒤입니다.
x 쓰기 전용입니다. 포인트는 맨 앞입니다. 파일이 존재하면 에러가 발생합니다.
x+ 쓰기 + 읽기입니다. 이 모드는 x와 같습니다.
c 쓰기 전용입니다. 포인트는 맨 앞이며, 이 모드로 작성되는 내용은 내용이 잘리지 않습니다. (테스트 결과 잘리던데????!!)
c+ 쓰기 + 읽기입니다. 이 모드는 c와 같습니다.
e 열린 파일 디스크립터에서 close-on-exec 플래그를 설정해야 합니다. POSIX.1-2008 호환 시스템에서 컴파일 된 PHP에서만 사용할 수 있습니다.

메뉴얼에는 이렇게 쓰여 있는데... 저는 r,w,a 밖에 사용하지 않아서 다른 내용은 크게 잘 모르겠네요.

「+」표시가 있어서 읽기 쓰기 동시에 사용하는 경우가 있는데, 개인적으로 좋지 않습니다. 특히 r+로 해서 작성을 하면 포인트가 맨 앞에 있기 때문에 내용이 추가가 되는 것이 아니라 기존 내용에서 내용이 바뀌어 버립니다.

사양에 따라 작성할 수도 있지만, 대부분은 예상치 못한 결과가 나올 것입니다.


그냥 간단하게 파일 읽기는 r, 새로 쓰기는 w, 기존 파일에 아래쪽으로 추가하는 것은 a정도가 되겠네요..

<?php
  if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // 파일을 업로드를 받으면 name과 tmp_name(임시 파일) 경로가 나온다.
    $name = $_FILES["data"]["name"];
    $path = $_FILES["data"]["tmp_name"];
    try {
      // 임시 파일에서 바이너리 형식으로 데이터를 받는다.
      if (@$handle = fopen($path, 'rb')) {
        $binary = fread($handle, filesize($path));
      }
    } catch (Exception $e) {
      print_r($e);
    } finally{
      @fclose($handle);
    }
    try {
      // 임시 파일에서 바이너리 형식으로 데이터를 작성한다.
      if (@$handle = fopen($name, 'wb')) {
        fwrite($handle, $binary);
      }
    } catch (Exception $e) {
      print_r($e);
    } finally{
      @fclose($handle);
    }
  }
?>
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
  <form method="POST" enctype="multipart/form-data">
    <input type="file" name="data">
    <input type="submit">
  </form>
</body>
</html>

위 소스는 브라우저에서 파일 업로드하면 저장하는 소스입니다. 여기서 fopen을 보면 b가 붙어있습니다. 이는 string형식이 아닌 바이너리 형식입니다.

파일 업로드가 잘 되었습니다. 참고로 실제 프로그램을 작성할 때는 업로드 파일을 서버에 그대로 올리는 것은 위험합니다. php파일로 올려서 악의적으로 해킹할 수 있기 때문입니다.

그 외에 업로드 파일은 txt형식이라면 바이너리로 받는 것이 아니라 그냥 string으로 받아서 처리하는 것도 가능합니다.

참조 - https://www.php.net/manual/en/function.fread.php

참조 - https://www.php.net/manual/en/function.fopen.php

참조 - https://www.php.net/manual/en/function.fwrite.php


여기까지 PHP에서 사용하는 IO에 관한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.