티스토리 뷰

오늘도 개발자/PHP

[PHP] 파일(file)

오늘도공대생 2022. 1. 31. 14:29

 

파일 업로드시 최대 크기는 php.ini 설정에서 upload_max_filesize 설정을 통해 조절할 수 있고

max_file_uplads 설정은 한 번에 몇개 까지 동시에 파일을 올릴 수 있는지 설정합니다.

 

  • dirname() - 상위 디렉토리의 경로를 반환합니다.
  • basename() - 경로의 후행 이름 구성 요소를 반환합니다.
  • parse_url() - URL을 구문 분석하고 해당 구성 요소를 반환합니다.
  • realpath() - 정규화된 절대 경로 이름을 반환 합니다.

 

 

pathinfo(string $path, int $flags = PATHINFO_ALL): array|string

$path에 따라 연관 배열 또는 문자열에대한 정보를 반환합니다

  • 현재 경로 정보 검색에 대한 정보는 사전 정의된 예약 변수 섹션을 참조하세요
  • 입력 문자열에 대해 정직하게 작동하며 실제 파일 시스템이나  "..".와 같은 경로 구성 요소를 인식하지 못합니다.
  • 지정되지 않을 경우 반환 :  dirname, basename, extension, filename
    $path_parts = pathinfo('/www/htdocs/inc/lib.inc.php');
    
    echo $path_parts['dirname'], "\n";
    echo $path_parts['basename'], "\n";
    echo $path_parts['extension'], "\n";
    echo $path_parts['filename'], "\n";
    /* 위의 예는 다음을 출력합니다.
    /www/htdocs/inc 
    lib.inc.php 
    PHP 
    lib.inc
    */

 

 

예 #1. 파일 업로드와 확장자 체크

switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        echo <<< 'HTML'
<form action+"/" method="post" enctype="multipart/form-data">
    <input type="file" name="uploads">
    <input type="submit">
</form>
HTML;
        break;
    case 'POST':
        $file = $_FILES['uploads'];
        $pathinfo = pathinfo($file['name']);
        // 확장자 체크
        $accepts = [
            'png', 'jpg'
        ];
        if(in_array(strtolower($pathinfo['extension']), $accepts) && is_uploaded_file($file['tmp_name'])) {
            move_uploaded_file($file['tmp_name'], dirname(__FILE__).'/uploads/'. $file['name']);
        }
        
        break;
}

만약, 파일 이름에 제약을 두고 싶다면 $file['name']에 정규표현식을 이용합니다.

 

 

 

예 #2. 파일 다운로드(file download)

// $path = filter_input(INPUT_GET, 'path', FILTER_SANITIZE_STRING);
$path = './README.md';	// 파일 위치

header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename='.basename($path));
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($path));

readfile($path);

이 경우 $path에 담긴 경로는 상대 경로로 직접 접근할 수 있기 때문에 보안상 문제가 발생 할 수 있습니다.

이를 막기 위해 아래와 같이 $path에 담긴 상대 경로들을 모두 제거해주고 연결해주시면 됩니다.

 

realpath(string $path): string|false

정규화된 절대 경로 이름을 반환 합니다.

/./  또는 /../ 그리고 후행 구분 기호도 제거됩니다.

chdir('/var/www/');
echo realpath('./../../etc/passwd') . PHP_EOL;
echo realpath('/tmp/') . PHP_EOL;
/*위의 예는 다음을 출력합니다.
/etc/passwd 
/tmp
*/

 

예 #2-1. 파일 다운로드 - 상대 경로 제거

$path = './README.md';
$filepath = realpath(dirname(__DIR__).'/uploads/'.basename($path));

header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename='.basename($path));
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($path));

readfile($path);

 

 

allow_url_fopen과 allow_url_include

php.ini 파일에 있는 설정입니다. 이는 file_get_contents()

file_get_contents(
    string $filename,
    bool $use_include_path = false,
    ?resource $context = null,
    int $offset = 0,
    ?int $length = null
): string|false

 

이 함수는 file_get_contents() 가 지정된 최대 바이트 에서 시작하여 문자열 로 파일을 반환 한다는 점을 제외하면 file() 과 유사합니다.

 

예제 #1 웹 사이트의 홈페이지 소스 가져오기 및 출력

$homepage = file_get_contents('http://www.example.com/');
echo $homepage;

예제 #2 include_path 내에서 검색하기

// If strict types are enabled i.e. declare(strict_types=1);
$file = file_get_contents('./people.txt', true);
// Otherwise
$file = file_get_contents('./people.txt', FILE_USE_INCLUDE_PATH);

예제 #3 파일의 섹션 읽기

// Read 14 characters starting from the 21st character
$section = file_get_contents('./people.txt', FALSE, NULL, 20, 14);
var_dump($section);

allow_url_include 설정이 켜져 있을 경우 URL을 include로 열 수 있습니다. 이 또한 치명적인 문제가 될 수 있기 때문에 해당 설정은 꺼주는 것이 좋습니다.

'오늘도 개발자 > PHP' 카테고리의 다른 글

[PHP] 세션(Session)  (0) 2022.02.02
[PHP] 사전 정의된 변수(Predefined Variables)  (0) 2022.02.02
[PHP] 에러 리포팅(Error Reporting)  (0) 2022.01.31
[PHP] MySQLi  (0) 2022.01.31
[PHP]System program execution  (0) 2022.01.31
댓글