PHP Windows создание расширения (Visual Studio 2008 (VS9) C++ Express) - php 5 extension -пример исходного кода

Друзья, изрядно "помыкавшись" мне наконец-то получить
работающее расширение для PHP 5 (php 5.3.8) - "просто чтобы заработало", "рабочим" оказался вариант приведённый на хабре.

Но я позволю себе ещё раз немного прокомментировать процесс.
Что скачать
Нам понадобятся:

  1. Студия 2008 (Visual Studio 2008 (VS9) C++ Express - т.е. можно использовать бесплатную версию)
  2. Исходники PHP (в статье ниже их предлагается разместить в папке php-5.3.6\)
  3. Уже собранный php под windows - "бинарники" (ниже для них предлагается использовать папку D:\Program Files\php-5.3.6-Win32-VC9-x86\ -но у вас она может быть иной - я просто поя)

И бинарники и исходники (выбирайте одну конкретную версию - версии их, вообще говоря, должны совпадать)
качайте с официального сайта: http://php.net/releases/index.php

Настройка среды

Для начала создадим проект типа Win32 Console Application и выберем DLL в Application type. Теперь нам придется настроить все зависимости и пути для линковщика:

Щелкните правой кнопкой мыши в Solution Explorer'e и выберите

 Properties > C/C++ > General > Additional Include Directories. 

Сюда мы добавим директории, в которых лежат распакованные исходники и заголовочные файлы PHP. Конкретно нужны будут:

   php-5.3.6
    php-5.3.6\main
    php-5.3.6\TSRM
    php-5.3.6\Zend

Теперь добавим preprocessor definitions, которые нужны для корректного выбора платформы и компиляции модуля. Выбираем

Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions

, и добавляем туда следующее:

    PHP_WIN32
    ZEND_WIN32
    ZTS=1
    ZEND_DEBUG=0

Затем укажем линковщику где можно найти необходимые библиотеки. Выбираем Configuration Properties > Linker > General > Additional Library Directories. Там выбираем директорию \dev из бинарников PHP. Должно получиться что-то такое:

 D:\Program Files\php-5.3.6-Win32-VC9-x86\dev

Теперь укажем конкретную либу для линковщика. Идем в Configuration Properties > Linker > Input > Additional Dependencies, и вписываем туда php5ts.lib, которая находится в той самой \dev директории, которую мы указали в предыдущем шаге.

Для избегания некоторых проблем компиляции, добавим директиву

/FORCE:MULTIPLE

в

Configuration Properties > Linker > Command Line.

Подробнее о ней можно прочитать на сайте MSDN.

И, наконец, можно указать, куда сохранять скомпилированную dll. Для этого перейдем в Configuration Properties > Linker > General > Output Filename и укажем там путь к папке \ext установленного PHP. Должно получиться что-нибудь такое:

«D:\Program Files\php-5.3.6-Win32-VC9-x86\ext\$(ProjectName).dll».

Код расширения

Итак - код самого расширения выглядит так (пишем его в основном файле - он совпадает с именем проекта, которые вы задали при создании проекта в 2008-ой студии ):


#include "stdafx.h"

PHP_FUNCTION(test);

const zend_function_entry test_functions[] = {
    PHP_FE(test, NULL)
    {NULL, NULL, NULL}
};

zend_module_entry test_module_entry = {
    STANDARD_MODULE_HEADER,       // #if ZEND_MODULE_API_NO >= 20010901
    "test",                       // название модуля
    test_functions,               // указываем экспортируемые функции
    NULL,                         // PHP_MINIT(test), Module Initialization
    NULL,                         // PHP_MSHUTDOWN(test), Module Shutdown
    NULL,                         // PHP_RINIT(test), Request Initialization
    NULL,                         // PHP_RSHUTDOWN(test), Request Shutdown
    NULL,                         // PHP_MINFO(test), Module Info (для phpinfo())
    "0.1",                        // версия нашего модуля
    STANDARD_MODULE_PROPERTIES
};

ZEND_GET_MODULE(test) // это и есть официальное имя нашего модуля 

PHP_FUNCTION(test)
{
	RETURN_STRING("MEMO =)", 1);  // возвращаем PHP-строку, второй параметр указывает, нужно ли копировать строку в памяти или нет
}

а упомянутый в нём файл stdafx.h (измените содежимое на следующее) так:

#ifndef STDAFX
 
#define STDAFX
#define PHP_COMPILER_ID "VC9"    // эту опцию мы указываем для совместимости с PHP, скомпилированным Visual C++ 9.0
#include "zend_config.w32.h"
#include "php.h"
 
#endif

Также необходимо произвести все настройки указанные в "хабростатье" (определить необходимые константы и опции).

Если вы попытаетесь скомпилировать проект на данном этапе, вы получите ошибку, говорящую о том, что отсутствует main\config.w32.h. Его можно получить либо запустив скрипт main\configure.bat, либо можно выдернуть его из исходников, например версии PHP 5.2. При этом не забываем отредактировать в этом файле все пути и раскомментировать директиву

"#define HAVE_SOCKLEN_T"

.
Теперь проект должен скомпилироваться без ошибок.

На данном этапе ваша цель - увидеть в области уведомления о событиях сборки (нижняя часть окна студии) строку вроде (она будет в конце списка сообщений):

========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Подключение расширения

Указанный выше проект собирался мною в 2008-ой студии как dll, которая имела имя

 php_tutorial.dll

(да-да -имя динамической как выясняется для вызова функции в данном контексте значения не имеет)
Получившуюся dll надо поместить в папку которая указана в опции extension_dir файла конфигурации php.ini
например:

 extension_dir = "C:/php/ext"

Соответственно в данное расширение (собранное из кода указанного выше имело) подключалось таким образом (смотрите последнюю строку):

extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
;extension=php_pdo_sqlite.dll
;extension=php_pgsql.dll
;extension=php_pspell.dll
;extension=php_shmop.dll
extension=php_tutorial.dll

После того ,как вы добавили dll необходимо перезапустить сервер.

Тестирование пользовательского расширения

протестировать новоиспечённое расширение можно выполнив в командной строке команду
(путь к php.exe должен быть включён в path):

php -r "echo test();"

В качестве ответа вы должны увидеть:

MEMO =)

Конечно - теперь функцию можно вызывать из из php скрипта:

<?php

echo "This link func answer: ".test(true);

Если расширение заработало - то можно попытаться передать параметры в функцию

Передача параметров в функцию пользовательского расширения PHP