Getting Started (Environment Setup)
Create a project directory and add Dockerfile
FROM centos:7
# Install dependencies
RUN yum -y install gcc gcc-c++ gdb autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers gd gd2 gd-devel gd2-devel perl-CPAN pcre-devel libicu-devel wget
# Download specific PHP version
RUN wget -O /tmp/php.tar.gz https://www.php.net/distributions/php-7.1.0.tar.gz
RUN mkdir ~/php71 && tar -xvf /tmp/php.tar.gz --strip-components 1 -C ~/php71
# Installation directory: /var/php71
# Source directory: /var/www
###################################################################
# 1. Generate Makefile
# 2. Compile
# 3. Install
RUN cd ~/php71 && \
./configure --prefix=/var/php71 --enable-fpm --enable-debug --enable-phpdbg-debug CFLAGS="-g3 -gdwarf-4" && \
make && \
make install
# Configure PHP & FPM
RUN cp ~/php71/php.ini-production /var/php71/lib/php.ini && \
cp /var/php71/etc/php-fpm.conf.default /var/php71/etc/php-fpm.conf && \
echo $'export PATH=$PATH:/var/php71/bin:/var/php71/sbin' >> ~/.bashrc
# Install Nginx for FPM debugging
RUN yum -y install epel-release && \
yum -y install nginx
# Nginx FPM configuration
RUN echo $'server {\n\
listen 9999;\n\
root /var/www;\n\
location / {\n\
root /var/www;\n\
index index.php index.html index.htm;\n\
}\n\
error_page 500 502 503 504 /50x.html;\n\
location ~ \.php$ {\n\
fastcgi_pass 127.0.0.1:9000;\n\
fastcgi_index index.php;\n\
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n\
include fastcgi_params;\n\
}\n\
}' > /etc/nginx/conf.d/fpm.conf
# FPM worker configuration
RUN echo $'[www]\n\
user = nobody\n\
group = nobody\n\
listen = 127.0.0.1:9000\n\
pm = static\n\
pm.max_children = 1' > var/php71/etc/php-fpm.d/www.conf
Create docker-compose.yml
in project directory
version: '3'
services:
centos:
build: ./
tty: true
cap_add:
- SYS_PTRACE
working_dir: /var/www
volumes:
- ./:/var/www
ports:
- 9999:9999
Build and start container
docker-compose up -d && docker-compose exec centos bash
Debugging with GDB
docker-compose exec centos bash
# Launch TUI mode
gdb --tui
# Debug executable
gdb php
# Attach to process
gdb --pid=xxx
Common Commands |
Description |
run |
Restart program |
start |
Step-by-step execution from start |
list |
View source code (l) |
set |
Set variable values |
next |
Step over (n) |
step |
Step into (s) |
break |
Set breakpoint (b) |
delete |
Delete breakpoint |
finish |
Exit current function |
continue |
Resume execution (c) |
print |
Print values (p) |
quit |
Exit GDB (q) |
info |
View local variables (i) |
Debugging PHP-FPM
- Configured with single worker process for easier tracing
docker-compose exec centos bash
php-fpm
nginx
# Find worker process ID
ps aux | grep fpm
gdb --pid=xxx
- Use Understand for code navigation
- Download matching PHP version source code for analysis
Adding Extensions (Optional)
- Requirements:
- PHP source matching installed version
- Steps (e.g., curl extension):
cd ~/php71/ext/curl
/var/php71/bin/phpize
./configure --with-php-config=/var/php71/bin/php-config
make && make install
Byte Alignment Example
struct A
{
int a; // 4 bytes
char b; // 1 byte
short c; // 2 bytes (aligned to 2n)
char d; // 1 byte
};
/* Memory layout: aaaa b0cc d000 (Total 12 bytes) */
Endianness
- Big-Endian:
0x1A2B3C4D
→ 0x1A | 0x2B | 0x3C | 0x4D
- Little-Endian:
0x1A2B3C4D
→ 0x4D | 0x3C | 0x2B | 0x1A
Variable Storage (ZVAL)
typedef union _zend_value {
zend_long lval; // Integer
double dval; // Double
zend_refcounted *counted; // Reference counted types
zend_string *str; // String
zend_array *arr; // Array
// ... other types
} zend_value;
struct _zval_struct {
zend_value value; // Actual value
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, // Variable type
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info;
} u1;
// ... other fields
};
PHP Execution Flow
- Lexical Analysis: Convert source to tokens
- Parsing: Generate Abstract Syntax Tree (AST)
- Compilation: Produce OPcodes
- Zend VM: Execute OPcodes as machine code
Lifecycle
CLI Mode
php_module_startup → php_request_startup → php_execute_script → php_request_shutdown → php_module_shutdown
FPM Mode
┌─────────────────────┐
│ fcgi_accept_request│
└─────────────────────┘
▲
php_module_startup│
│
php_request_startup
│
php_execute_script
│
php_request_shutdown
│
php_module_shutdown
FAQ
- Struct Hack:
char[1]
in zend_string
enables single memory allocation
- Typedef Conventions:
- Global types defined in headers
- File-local types declared with structs
- FPM Process Management:
- Master process manages workers
kill -9
on master leaves workers running