Оглавление
Внутреннее устройство PHPСоздание базового расширенияРабота с параметрами и типами данныхПолезный пример: быстрый подсчёт частот словДобавление системы лицензированияЗаключение: когда стоит использовать этот подход?Финальные советы:
Создание расширения PHP на C
01.05.2026

PHP достаточно быстр, но до тех пор, пока не перестаёт им быть. Есть задачи, с которыми не справится никакой PHP: обработка миллионов элементов в циклах, бинарный парсинг, криптография, интеграция с C-библиотеками без PHP-обвязки. Здесь два пути: смириться с узким местом или спуститься на уровень ниже.
PHP-расширения позволяют писать код на C, который выполняется прямо внутри процесса PHP, то есть без подпроцессов, сокетов и сериализации. Ваша C-функция становится полноценной PHP-функцией, вызываемой как любая другая.
Есть и вторая причина для написания расширений, о которой редко говорят: распространение. Если вы создаёте коммерческий PHP-продукт (SDK, проприетарный алгоритм, модуль), доставка скомпилированного файла
.so - лучший способ защитить логику. Исходный код остаётся у вас.В этой статье вы узнаете, как создать настоящее PHP-расширение с нуля и добавить слой проверки лицензии, чтобы оно отказывалось работать без авторизации.
Внутреннее устройство PHP
Движок Zend
PHP не исполняет исходный код напрямую. Сначала он компилирует его в опкоды, а затем виртуальная машина Zend Engine выполняет эти опкоды. При вызове PHP-функции Zend Engine ищет её в глобальной таблице функций и передаёт управление.
Расширения подключаются к этому процессу на уровне C: они регистрируют функции, классы и константы в таблицах Zend Engine при запуске, ещё до выполнения первой строки PHP-скрипта.
Это похоже на систему плагинов, встроенную в сам рантайм. Для движка неважно, определена ли функция на PHP или на C. К моменту вызова она просто запись в хеш-таблице, указывающая на указатель C-функции.
Что такое PHP-расширение?
Расширение - это динамическая библиотека (
.so в Linux, .dll в Windows), которую PHP подгружает при старте согласно настройкам php.ini. Оно предоставляет модульную запись - структуру на C, сообщающую PHP имя, версию и хуки жизненного цикла.Эта структура - контракт между вашим кодом и рантаймом PHP.
Взаимодействие PHP и C
PHP передаёт аргументы в C-функции через абстракцию стека. Возвращаемые значения идут через специальный указатель
return_value. Связь между динамической системой типов PHP и статической системой типов C обеспечивает структура zval (об этом ниже).Zend API предоставляет макросы для всего: парсинга аргументов, возврата значений, генерации исключений, выделения памяти. Вы редко работаете с «сырыми» указателями - макросы всё делают за вас.
Создание базового расширения
Структура файлов
Минимальное расширение требует трёх файлов:
Заголовочный файл
Конфигурация сборки (config.m4)
Основной файл на C (myext.c)
Сборка и установка
Добавьте в
php.ini:Проверьте:
Работа с параметрами и типами данных
Структура zval
Любое значение PHP (строка, число, массив, объект) на уровне C представляется как
zval - это tagged union: хранит значение и флаг типа вместе.Вы редко будете создавать zval вручную, макросы всё сделают за вас.
Парсинг параметров
Макрос
ZEND_PARSE_PARAMETERS_START автоматически занимается приведением типов, проверкой количества аргументов и ошибками.Возврат значений
Пример для строк:
Используйте аллокаторы Zend (emalloc, efree) вместо стандартных malloc/free.
Полезный пример: быстрый подсчёт частот слов
Вызов из PHP:
Всегда используйте estrndup/efree внутри расширений.
Добавление системы лицензирования
Проблема
Вы скомпилировали расширение в
.so. Клиент покупает лицензию, разворачивает файл на десяти серверах и вы не контролируете это. Обфускация не спасёт: опытный разработчик быстро разберёт .so. Нужна проверка лицензии при каждом запуске (или периодически), чтобы расширение отказывалось работать без успешной проверки.Подход
Надёжная система лицензирования обычно включает:
- Удалённую проверку через API.
- Привязку к домену или IP.
- Локальное кэширование результата (с истечением срока).
Реализация проверки лицензии на C
Важно: всегда используйте HTTPS и проверяйте сертификаты (CURLOPT_SSL_VERIFYPEER=1).
Блокировка выполнения при загрузке модуля
Проверку лицензии лучше всего делать в хуке инициализации модуля (
PHP_MINIT):Если проверка не прошла, то функции не регистрируются и расширение не работает.
Настройка php.ini
Пример серверной части (PHP)
Вопросы безопасности
- Локальная проверка легко обходится: ключ можно найти через strings, objdump.
- Удалённая проверка надёжнее только если расширение действительно не работает без ответа сервера.
- Реверс-инжиниринг: даже скомпилированный код можно разобрать инструментами вроде Ghidra или IDA Pro.
- Не храните ключи в бинарнике; используйте подписи ответов (HMAC/асимметричные ключи).
- Всегда проверяйте TLS; не доверяйте "сырым" JSON.
- Базовая обфускация: удалите символы из
.soкомандойstrip --strip-all. - Для защиты более ценной интеллектуальной собственности рассмотрите обфускаторы типа Obfuscator-LLVM.
Архитектура для продакшна: гибридная модель
Сочетайте три уровня защиты:
- PHP-приложение вызывает ваше расширение.
- Расширение при инициализации связывается с вашим API для проверки лицензии (и кэширует результат).
- Чувствительные операции проксируются через ваш API; логика остаётся на сервере.
- Периодическая ревалидация: например, каждые N запросов или M минут.
Заключение: когда стоит использовать этот подход?
Создавайте расширение PHP на C если:
- Профилирование подтвердило узкое место по производительности.
- Вы интегрируете библиотеку без PHP-обвязки.
- Вам нужно распространять коммерческий продукт без раскрытия исходников.
- Требуется внешняя по отношению к пользовательскому пространству PHP система лицензирования.
Не пишите расширение просто потому что "PHP кажется медленным". Сначала профилируйте. Расширения усложняют сборку и деплой, используйте их только если это действительно нужно.
Финальные советы:
Перед выпуском расширяйте систему лицензирования:
- Подписывайте ответы сервера (HMAC/асимметричные подписи).
- Проверяйте срок действия лицензии прямо в C.
- Добавляйте "окно" для сетевых сбоев (не убивайте прод из-за недоступности сервера лицензий).
- Ведите аудит обращений к серверу лицензий.
- Реализуйте механизм быстрой блокировки недобросовестных пользователей без обновления бинарника.
Самое сложное здесь - найти баланс между защитой интеллектуальной собственности и стабильной работой продакшн-систем клиентов. Если сделать всё правильно, то получится решение устойчивое к пиратству и безопасное для бизнеса.

