- XSS방어
- Mac Oracle
- 404에러페이지
- simpe ftp
- ViewData
- asp.net core Select
- javascript redirection
- 말줄임표시
- jquery 바코드생성
- asp ftp
- 맥 오라클설치
- SSD 복사
- 강제이동
- 하드 윈도우 복사
- asp.net dropdownlist
- JavaScript
- 하드 마이그레이션
- 타임피커
- django 엑셀불러오기
- swagger 500 error
- 바코드 생성하기
- javascript 바코드 생성
- ASP.Net Core 404
- 원격ftp
- ViewBag
- php 캐쉬제거
- TempData
- asp.net core swagger
- asp.net Select
- XSS PHP
웹개발자의 기지개
[PHP] PHP7 에서 PHP8 마이그레이션할때 주의할 점 본문
[주의할 점]
1. 정의되지 않은 배열 인덱스 접근
2. count()에 배열 아닌 값 전달
3. 문자열/숫자 비교의 엄격성 변화
4. 오래된 함수 사용
5. each(), create_function() 등 제거
6. mysqli / PDO 사용 방식 문제
7. null 처리 문제
8. 필수/선택 파라미터 순서 문제
1. 짧은 배열/변수 접근 전 undefined 문제
[PHP7]
$user_name = $_GET['user_name'];
[PHP8]
$user_name = $_GET['user_name'] ?? '';
$page = (int)($_GET['page'] ?? 1);
[PHP7]
$mode = $_REQUEST['mode'];
if ($mode == 'write') {
...
}
[PHP8]
$mode = $_REQUEST['mode'] ?? '';
if ($mode === 'write') {
...
}
2. count() 에 null 넣는 문제
[PHP7]
if (count($arr) > 0) {
...
}
[PHP8]
if (is_array($arr) && count($arr) > 0) {
...
}
$arr = $arr ?? [];
if (count($arr) > 0) {
...
}
파일업로드 예시 코드
[PHP7]
if (count($_FILES['upfile']['name']) > 0) {
...
}
[PHP8]
$fileNames = $_FILES['upfile']['name'] ?? [];
if (is_array($fileNames) && count($fileNames) > 0) {
...
}
3. explode(), trim(), strlen() 등에 null 전달 문제
[PHP7]
$name = trim($_POST['name']);
$tags = explode(',', $_POST['tags']);
$len = strlen($_POST['title']);
[PHP8]
$name = trim($_POST['name'] ?? '');
$tags = explode(',', $_POST['tags'] ?? '');
$len = strlen($_POST['title'] ?? '');
4. 숫자/문자열 비교 느슨한 코드 수정 - 비교 동작이 더 엄격하게 적용됨
[PHP7]
if ($_GET['no'] == 0) {
...
}
if ($member_level == '1') {
...
}
[PHP8]
$no = (int)($_GET['no'] ?? 0);
if ($no === 0) {
...
}
if ($member_level === 1) {
...
}
5. optional parameter before required parameter 문제
: 선택 파라미터가 필수 파라미터보다 앞에 있으면 문제
[PHP7]
function myFunc($title = '', $name) {
return $title . $name;
}
function uploadFile($dir = '', $fileName, $tmpName)
[PHP8]
function myFunc($name, $title = '') {
return $title . $name;
}
function uploadFile($fileName, $tmpName, $dir = '')
6. each() 함수 제거
[PHP7]
reset($arr);
while (list($key, $val) = each($arr)) {
echo $key . ' => ' . $val;
}
[PHP8]
foreach ($arr as $key => $val) {
echo $key . ' => ' . $val;
}
7. create_function() 제거
[PHP7]
$func = create_function('$a,$b', 'return $a+$b;');
echo $func(1, 2);
[PHP8]
$func = function($a, $b) {
return $a + $b;
};
8. preg_replace / 문자열 처리 부분 점검
: 정규식 옵션이나 null 전달 문제를 확인해야 함
[PHP7]
$str = preg_replace("/\s+/", " ", $str);
: /e modifier 쓰는 경우가 있으면 반드시 수정해야 함
[PHP8]
$str = preg_replace("/\s+/", " ", $str ?? '');
$str = preg_replace_callback("/(\d+)/", function($matches) {
return myfunc($matches[1]);
}, $str ?? '');
9. session / cookie 처리 점검
[PHP7]
setcookie("save_id", $user_id, time()+86400);
setcookie('save_id', $user_id, [
'expires' => time() + 86400,
'path' => '/',
'secure' => false, // HTTPS면 true 권장
'httponly' => true,
'samesite' => 'Lax'
]);
10. mysqli 구형 스타일 혼합 코드 정리
[PHP7]
$conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
$sql = "select * from member where user_id='$user_id'";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($result);
[PHP8] - SQL 인젝션 방지
$conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
if (!$conn) {
die('DB 연결 실패: ' . mysqli_connect_error());
}
$user_id = $_POST['user_id'] ?? '';
$stmt = mysqli_prepare($conn, "SELECT * FROM member WHERE user_id = ?");
mysqli_stmt_bind_param($stmt, "s", $user_id);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
11. mysql_* 함수 사용 중이면 반드시 수정
PHP5 에서 이용하던
mysql_connect(...);
mysql_query(...);
mysql_fetch_array(...);
코드 수정할 것.
[PHP8]
$conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
$result = mysqli_query($conn, "SELECT * FROM board");
while ($row = mysqli_fetch_assoc($result)) {
echo $row['subject'];
}
12. include / require 경로 문제 더 엄격하게 점검
[PHP7]
include "lib.php";
include "../dbconn.php";
[PHP8]
include __DIR__ . "/lib.php";
include __DIR__ . "/../dbconn.php";
13. 회원가입 입력값 처리
[PHP7]
$user_id = trim($_POST['user_id']);
$user_pw = trim($_POST['user_pw']);
$user_name = trim($_POST['user_name']);
if ($user_id == '' || $user_pw == '' || $user_name == '') {
die('필수값 누락');
}
[PHP8]
$user_id = trim($_POST['user_id'] ?? '');
$user_pw = trim($_POST['user_pw'] ?? '');
$user_name = trim($_POST['user_name'] ?? '');
if ($user_id === '' || $user_pw === '' || $user_name === '') {
die('필수값 누락');
}
14. 비밀번호 저장 방식 개선
[PHP7]
$user_pw = md5($_POST['user_pw'] ?? '');
$user_pw = sha1($_POST['user_pw'] ?? '');
[PHP8]
$user_pw = $_POST['user_pw'] ?? '';
$hash_pw = password_hash($user_pw, PASSWORD_DEFAULT);
// 로그인 확인
$input_pw = $_POST['user_pw'] ?? '';
$db_pw = $row['user_pw'] ?? '';
if (password_verify($input_pw, $db_pw)) {
echo "로그인 성공";
} else {
echo "로그인 실패";
}
15. 게시판 글쓰기 처리
[PHP7]
$subject = addslashes($_POST['subject']);
$content = addslashes($_POST['content']);
$sql = "insert into board set subject='$subject', content='$content'";
mysqli_query($conn, $sql);
[PHP8]
$subject = trim($_POST['subject'] ?? '');
$content = trim($_POST['content'] ?? '');
mysqli_stmt_bind_param($stmt, "ss", $subject, $content);
mysqli_stmt_execute($stmt);
16. 게시판 상세보기
[PHP7]
$no = $_GET['no'];
$sql = "select * from board where no='$no'";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($result);
[PHP8]
$stmt = mysqli_prepare($conn, "SELECT * FROM board WHERE no = ?");
mysqli_stmt_bind_param($stmt, "i", $no);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
17. 게시판 목록 페이징
[PHP7]
$page = $_GET['page'];
if (!$page) $page = 1;
$start = ($page - 1) * 10;
$sql = "select * from board order by no desc limit $start, 10";
[PHP8]
$page = (int)($_GET['page'] ?? 1);
if ($page < 1) $page = 1;
$start = ($page - 1) * 10;
$limit = 10;
$sql = "SELECT * FROM board ORDER BY no DESC LIMIT $start, $limit";
$page = (int)($_GET['page'] ?? 1);
$start = (int)$start;
$limit = (int)$limit;
18. 문자열 함수에 배열 전달
[PHP7]
echo htmlspecialchars($_POST['name']);
[PHP8]
$name = $_POST['name'] ?? '';
if (!is_string($name)) {
$name = '';
}
echo htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
19. foreach 대상이 배열이 아닌 경우
[PHP7]
foreach ($list as $row) {
echo $row['name'];
}
[PHP8]
$list = is_array($list ?? null) ? $list : [];
foreach ($list as $row) {
echo $row['name'] ?? '';
}
20. implode() 인자 순서 헷갈림 - 표준 순서대로
[PHP7]
$str = implode($arr, ',');
[PHP8]
21. substr(), strpos() 에서 false/null 처리
[PHP7] - 맨 앞에 @ 이 있으면 0 이어서 false 가 된다.
echo '이메일형식';
}
echo '이메일형식';
}
22. 파일업로드 기능도 꼭 점검
[PHP7]
$filename = $_FILES['upfile']['name'];
$tmp_name = $_FILES['upfile']['tmp_name'];
move_uploaded_file($tmp_name, "./upload/".$filename);
[PHP8]
$uploadDir = __DIR__ . '/upload/';
if (!isset($_FILES['upfile']) || !is_array($_FILES['upfile'])) {
die('파일 정보가 없습니다.');
}
$filename = $_FILES['upfile']['name'] ?? '';
$tmpName = $_FILES['upfile']['tmp_name'] ?? '';
$error = $_FILES['upfile']['error'] ?? UPLOAD_ERR_NO_FILE;
if ($error !== UPLOAD_ERR_OK) {
die('업로드 오류');
}
$basename = basename($filename);
$saveName = time() . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $basename);
if (!move_uploaded_file($tmpName, $uploadDir . $saveName)) {
die('파일 저장 실패');
}
23. 마이그레이션용 공통 함수 만들어 놓기
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?
function post($key, $default = '')
{
return $_POST[$key] ?? $default;
}
function get($key, $default = '')
{
return $_GET[$key] ?? $default;
}
function h($str)
{
return htmlspecialchars((string)$str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
?>
|
cs |
$user_id = trim(post('user_id'));
$name = trim(post('name'));
$page = (int)get('page', 1);
echo h($name);
24. 마이그레이션 수정 우선 순위
1순위: 사이트가 죽는 치명 오류
each()
create_function()
함수 선언 파라미터 순서
null/array 타입 오류
include 경로 문제
2순위: 경고/Deprecated
undefined array key
trim/explode/strlen null 전달
count(null)
foreach(null)
3순위: 보안 개선
SQL 직접 문자열 조합
addslashes()
md5() 비밀번호
파일업로드 검증 부족
4순위: 코드 정리
공통 함수화
mysqli → PDO 또는 prepared statement 정리
중복 코드 제거
25. 예시 코드 정리
[PHP7]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?php
include "../dbconn.php";
$id = $_POST['id'];
$pw = $_POST['pw'];
if (!$id || !$pw) {
die("값이 없습니다.");
}
$sql = "select * from member where id='$id'";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($result);
if ($row['pw'] == md5($pw)) {
$_SESSION['ss_id'] = $row['id'];
echo "로그인 성공";
} else {
echo "로그인 실패";
}
?>
|
cs |
[PHP8]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<?php
session_start();
include __DIR__ . "/../dbconn.php";
$id = trim($_POST['id'] ?? '');
$pw = trim($_POST['pw'] ?? '');
if ($id === '' || $pw === '') {
die("값이 없습니다.");
}
$stmt = mysqli_prepare($conn, "SELECT id, pw FROM member WHERE id = ?");
mysqli_stmt_bind_param($stmt, "s", $id);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
if ($row && password_verify($pw, $row['pw'])) {
$_SESSION['ss_id'] = $row['id'];
echo "로그인 성공";
} else {
echo "로그인 실패";
}
?>
|
cs |
26. 마지막 정리
- $_GET, $_POST, $_SESSION 접근 시 ?? 처리
- count(null), foreach(null) 수정
- trim(null), explode(null) 수정
- each(), create_function() 제거
- 함수 파라미터 순서 수정
- SQL 직접 문자열 조합 → prepared statement
- md5/sha1 비밀번호 → password_hash / password_verify
- 파일업로드 검증 강화
- include 경로를 __DIR__ 기반으로 정리
'PHP' 카테고리의 다른 글
| [PHP] phpMyAdmin 에서 포트설정 (0) | 2026.03.14 |
|---|---|
| [PHP] OUTBOUND 443 가능 여부 확인하기 - discord 알림메세지 허용 (0) | 2026.02.16 |
| [PHP] 초간단 특정 파일의 접근 막기 (0) | 2026.01.30 |
| [PHP] phpinfo() 로 리눅스 환경 정보 구하기 (0) | 2025.11.20 |
| [PHP] 네이버페이, 카카오페이 연동하기 (0) | 2025.11.20 |
