OpenSource-Hub

php-src

기타

php/php-src

PHP 공식 인터프리터, Web 개발을 위한 스크립트 언어 엔진.

개요

php-src는 PHP 언어의 참조 구현체로, PHP는 특히 Web 개발에 적합한 인기 있는 범용 스크립트 언어입니다. 이 프로젝트는 C 언어로 작성되었으며 Zend 엔진, 다수의 내장 확장 및 완비된 테스트 스위트를 포함하고 있어 개인 블로그부터 글로벌 대형 웹사이트에 이르기까지 다양한 애플리케이션을 구동하고 있습니다.

README 미리보기

\n    \n        \n    \n\n\n# The PHP Interpreter\n\nPHP is a popular general-purpose scripting language that is especially suited to\nweb development. Fast, flexible and pragmatic, PHP powers everything from your\nblog to the most popular websites in the world.\n\nPHP is distributed under the [Modified BSD License](LICENSE)\n(SPDX-License-Identifier: `BSD-3-Clause`).\n\n[](https://github.com/php/php-src/actions/workflows/test.yml)\n[](https://issues.oss-fuzz.com/issues?q=project:php)\n\n## Documentation\n\nThe PHP manual is available at [php.net/docs](https://www.php.net/docs).\n\n## Installation\n\n### Prebuilt packages and binaries\n\nPrebuilt packages and binaries can be used to get up and running fast with PHP.\n\nFor Windows, the PHP binaries can be obtained from\n[windows.php.net](https://windows.php.net). After extracting the archive the\n`*.exe` files are ready to use.\n\nFor other systems, see the [installation chapter](https://www.php.net/install).\n\n### Building PHP source code\n\n*For Windows, see [Build your own PHP on Windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).*\n\nFor a minimal PHP build from Git, you will need autoconf, bison, and re2c. For\na default build, you will additionally need libxml2 and libsqlite3.\n\nOn Ubuntu, you can install these using:\n\n```shell\nsudo apt install -y pkg-config build-essential autoconf bison re2c libxml2-dev libsqlite3-dev\n```\n\nOn Fedora, you can install these using:\n\n```shell\nsudo dnf install re2c bison autoconf make ccache libxml2-devel sqlite-devel\n```\n\nOn MacOS, you can install these using `brew`:\n\n```shell\nbrew install autoconf bison re2c libiconv libxml2 sqlite\n```\n\nor with `MacPorts`:\n\n```shell\nsudo port install autoconf bison re2c libiconv libxml2 sqlite3\n```\n\nGenerate configure:\n\n```shell\n./buildconf\n```\n\nConfigure your build. `--enable-debug` is recommended for development, see\n`./configure --help` for a full list of options.\n\n```shell\n# For develo

FAQ (5)

문제 해결
PHP file_get_contents가 chunked HTTP 응답에서 실패할 때 filters.c/dechunk 필터의 'memory leaks detected' 오류를 해결하는 방법

이것은 PHP의 HTTP 스트림 래퍼에서 확인된 버그입니다(PHP 8.5.12 및 master 8.7.0-dev에서 재현됨). 응답이 Transfer-Encoding: chunked를 사용하면 래퍼는 헤더 파싱 중에 dechunk 필터를 생성합니다. 이후 헤더 라인의 형식이 잘못된 경우, 스트림이 NULL이기 때문에 에러 경로(php_stream_url_wrap_http_ex()의 out: 레이블)에서 필터가 해제되지 않아 실패한 요청당 96바이트가 누수됩니다(80바이트 필터 구조체 + 16바이트 dechunk 데이터). out: 정리(cleanup) 섹션에서 ext/standard/http_fopen_wrapper.c를 패치하여 수정하세요:

/* 에러 경로에서는 stream이 NULL이고 필터가 아래의
 * readfilters에 추가되지 않으므로, 여기서 해제해야 합니다. */
if (header_info.transfer_encoding != NULL && stream == NULL) {
    php_stream_filter_free(header_info.transfer_encoding);
    header_info.transfer_encoding = NULL;
}

이 코드를 efree(header_info.location); 바로 다음에 추가하세요(master 기준 약 1230번째 줄). 이 패치는 검증되었습니다: 재현 테스트에서 누수 0건이 보고되었고 형식이 올바른 chunked 응답은 영향을 받지 않습니다. 적용 후 소스에서 PHP를 다시 빌드하세요. 다시 빌드할 수 없는 경우, 누수는 작고(96바이트/요청) 잘못된 형식의 chunked 응답에서만 발생하므로, 프로덕션에서 report_memleaks를 비활성화하면 증상은 숨길 수 있지만 누수 자체는 수정되지 않습니다.

원본 Issue #24508
문제 해결
opcache.jit=1201에서 hooked property를 함수에 전달할 때 PHP가 segfault를 일으키는 이유는 무엇인가요?

이것은 PHP의 JIT 컴파일러 버그(GH-24398)로, 최적화 레벨 1(opcache.jit=1201, 1211, 1101, 1251)에서 함수 JIT에 영향을 미칩니다. get 훅이 있는 프로퍼티가 런타임에 해석되는 함수(예: 조건부로 선언되었거나 네임스페이스에서 한정되지 않은 이름으로 호출되는 함수)에 인자로 전달되면, JIT가 ZEND_FETCH_OBJ_FUNC_ARG를 잘못 처리하여 두 번째 호출에서 세그멘테이션 폴트(signal 11) 또는 ZEND_SEND_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER의 UBSan null-pointer offset 오류와 함께 충돌합니다. 수정 방법: GH-24402의 수정 사항(커밋 cfe77b82a6)이 포함된 PHP 버전으로 업그레이드하십시오. 그 전까지의 우회 방법: opcache.jit=disable로 설정하거나, opcache.jit=tracing으로 전환하거나, 1202, 1205, 1254와 같이 이 버그를 유발하지 않는 JIT 레벨을 사용하십시오.

원본 Issue #24398
문제 해결
세션 데이터 쓰기에 실패해도 session_write_close()가 true를 반환하는 이유는 무엇인가요?

이는 의도된, 문서화된 동작입니다(PHP 매뉴얼의 session_write_close() Return Values 섹션 참조). 이 함수는 활성 세션이 없을 때만 false를 반환하며, save handler의 write() 메서드가 실패하는 경우를 포함한 나머지 모든 경우에는 true를 반환합니다. 실패한 쓰기는 "session_write_close(): Failed to write session data using user defined save handler"와 같은 warning만 발생시킵니다.

쓰기 실패를 감지하기 위한 우회 방법:
1. 커스텀 SessionHandlerInterface 구현에서 자체 write() 메서드의 반환 값을 기록하고(예: 클래스 프로퍼티에 저장) session_write_close() 이후에 확인합니다.
2. 에러 핸들러로 warning을 포착합니다:

$writeFailed = false;
set_error_handler(function ($no, $msg) use (&$writeFailed) {
    if (str_contains($msg, 'Failed to write session data')) { $writeFailed = true; }
    return true;
});
session_write_close();
restore_error_handler();

쓰기 오류를 감지하기 위해 session_write_close() 반환 값에 의존하지 마세요.

원본 Issue #24561
문제 해결
opcache tracing JIT 사용 시 발생하는 PHP segfault (exit code 139) 또는 zend_jit_trace_exit 어설션 실패를 해결하는 방법

이는 tracing JIT에서 확인된 PHP 버그(GH-24389)입니다. 핫 트레이스에 인라인된 함수가 참조로 바인딩된 변수와 함께 호출되고 피연산자 타입이 변경되면(예: 반복 사이에 int → float), ZEND_JIT_TRACE_ENTER에서 레지스터에 할당된 callee CV에 대해 생성되는 타입 가드에 opline이 없기 때문에, 트레이스 종료 시 초기화되지 않은 EX(opline)을 읽게 됩니다. 릴리스 빌드에서는 세그폴트가 발생하고, 디버그 빌드에서는 ext/opcache/jit/zend_jit_trace.c에서 'zend_jit_trace_exit: Assertion ... opline ... failed'와 함께 중단됩니다.

수정: 크래시를 해결하는 커밋 b4ca62e317(PR GH-24411)이 포함된 빌드로 PHP를 업그레이드하세요.

업그레이드할 수 없는 경우의 우회 방법:
1. OPcache는 유지하면서 JIT 비활성화: php -d opcache.enable_cli=1 -d opcache.jit=disable로 실행하거나 php.ini에서 opcache.jit=disable로 설정하세요.
2. 호출 간에 값의 타입이 변경되는 핫 루프(예: int 배열을 순회한 후 float 배열을 순회하는 경우)에서는 참조 별칭($xr = &$x, foreach ($data as &$v))을 피하세요.

원본 Issue #24389
문제 해결
PHP에서 다른 serialize()가 진행 중일 때 __destruct() 안에서 serialize()를 호출하면 왜 segfault가 발생하거나 잘못된 백 참조가 생성되나요?

근본 원인: PHP의 serialize()는 재진입이 불가능합니다. php_var_serialize_destroy()가 외부 호출의 var_hash를 해제하는 도중에 소멸자가 실행되고(예: var_hash에 의해서만 살아 있던 객체이거나, 해제될 때 수집되는 GC 사이클인 경우) 그 소멸자가 serialize()를 호출하면, 중첩된 호출이 외부 var_hash를 재사용하게 됩니다. 결과: (1) 중첩된 출력이 잘못된 역참조를 갖게 됩니다(r:N 번호 매기기가 외부 호출에서 이어져서 r:2; 대신 r:6;가 출력됨); (2) 중첩 호출이 해시 테이블을 확장하면 외부 destroy가 해제된 메모리를 순회하게 되어 → use-after-free → Segmentation fault (exit 139)가 발생하며, 백트레이스는 zval_ptr_dtor → zend_hash_destroy → php_var_serialize_destroy → zif_serialize 순으로 나타납니다. PHP 8.4.26 및 8.5.11(NTS, 공식 php Docker 이미지)에서 확인되었으며, 테스트 스위트에서 간헐적으로 발생하는 segfault(예: TYPO3/PHPUnit에서 GC가 소멸자가 캐시 항목을 직렬화하는 DI 컨테이너를 수집하는 경우)의 근본 원인일 가능성이 높습니다. PHP 코어 수정이 적용되기 전까지의 우회 방법: 1) __destruct() 내부에서 serialize()(또는 이를 유발할 수 있는 어떤 것도)를 절대 호출하지 마세요 — 대신 작업을 지연시키거나 캐시하세요. 2) 테스트 스위트에서는 serialize() 직전에 gc_collect_cycles();를 호출하여 대기 중인 순환 가비지와 소멸자가 직렬화 컨텍스트 외부에서 실행되도록 하세요. 3) 객체가 직렬화되는 데이터를 통해서만 도달 가능한 상태가 되지 않도록 하세요. 재현 방법: __destruct()가 큰 배열에 대해 serialize()를 호출하는 클래스가 __serialize()를 통해 다른 객체 내부에서 직렬화되면 안정적으로 크래시가 발생합니다.

원본 Issue #24373