Writing PHP extensions for Windows–Writing the extension.

We are going to write a simple extension that contains one function. This function will take 2 numeric (long values) as parameters  and return the sum of these values. We will call the function as test_addMe(). It looks like this from a php script:

<?php
	echo test_addMe(1,2);
?>

Modify php.ini to include our extension, we will eventually drop our extension in the extension_dir “C:\PHP\EXT”.

1

From our project in Visual Studio 2010 previous article Writing PHP extensions for Windows–Building a compile environment modify phpTestModule.cpp :


#include "stdafx.h"

#define PHP_TEST_EXTNAME "test"
#define PHP_TEST_VERSION "1.0.30 Date:" __DATE__ " Time: " __TIME__



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

zend_module_entry test_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_TEST_EXTNAME,
test_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_TEST_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};


ZEND_GET_MODULE(test)


PHP_FUNCTION(test_addme)
{
long paramOne;
long paramTwo;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &paramOne,
&paramTwo) == FAILURE)
{
RETURN_FALSE;
}
RETURN_LONG(paramOne + paramTwo);
}

 

For a more details on Extension writing please review Zend Extension Writing .

Do a Build and drop phpTestModule.dll  in our extension directory.

You will notice that it doesn’t get included in our phpinfo() – index.php. The build was successful yet it does not get loaded. At this point we need to debug this with our Visual Studio 2010 debugger.

Debugging using Visual Studio 2010 remote debugger.

We are going to use Visual Studio 2010 remote debugger running in our Virtual Box setup. I will be discussing How to setup a debugging environment on a Virtual Box on a later date. Our target executable for debugging will be “C:\PHP\PHP-WIN.EXE”.

On our first run we get this error

3

Our main issue is our build ID, it does not match “PHP Extension Build”.

Note, all extensions are loaded by the macro ZEND_GET_MODULE(). ZEND_GET_MODULE() is responsible for passing the implemented functions to PHP. We place a breakpoint at this macro and then do our  debug run.

4

We display the contents of the variable test_module_entry. Note, build_id’s contents are displayed. The variable build_id is built via a macro called “STANDARD_MODULE_PROPERTIES”. The expansion is defined in php-5.4.28-src/Zend/zend_modules.h. Here’s a snippet from zend_mdoules.h

#define ZEND_MODULE_BUILD_ID "API" ZEND_TOSTR(ZEND_MODULE_API_NO) ZEND_BUILD_TS ZEND_BUILD_DEBUG ZEND_BUILD_SYSTEM ZEND_BUILD_EXTRA

#define STANDARD_MODULE_PROPERTIES_EX 0, 0, NULL, 0, ZEND_MODULE_BUILD_ID

#define NO_MODULE_GLOBALS 0, NULL, NULL, NULL

#ifdef ZTS
# define ZEND_MODULE_GLOBALS(module_name) sizeof(zend_##module_name##_globals), &module_name##_globals_id
#else
# define ZEND_MODULE_GLOBALS(module_name) sizeof(zend_##module_name##_globals), &module_name##_globals
#endif

#define STANDARD_MODULE_PROPERTIES \
	NO_MODULE_GLOBALS, NULL, STANDARD_MODULE_PROPERTIES_EX

//

Forming the ZEND_BUILD_ID relies on other macros that are given in php-5.4.28-src/Zend/zend_build.h.

#ifndef ZEND_BUILD_H
#define ZEND_BUILD_H

#define ZEND_TOSTR_(x) #x
#define ZEND_TOSTR(x) ZEND_TOSTR_(x)

#ifdef ZTS
#define ZEND_BUILD_TS ",TS"
#else
#define ZEND_BUILD_TS ",NTS"
#endif

#if ZEND_DEBUG
#define ZEND_BUILD_DEBUG ",debug"
#else
#define ZEND_BUILD_DEBUG
#endif

#if defined(ZEND_WIN32) && defined(PHP_COMPILER_ID)
#define ZEND_BUILD_SYSTEM "," PHP_COMPILER_ID
#else
#define ZEND_BUILD_SYSTEM
#endif

/* for private applications */
#define ZEND_BUILD_EXTRA 

#endif


After our analysis we need to modify our stdafx.h to produce an acceptable build_id. Like so,

#pragma once
#include "targetver.h"

#define WIN32_LEAN_AND_MEAN 
// Windows Header Files:
#include <windows.h>

//#define ZTS 1
#define PHP_COMPILER_ID "VC9"
#define ZEND_WIN32 1
#define PHP_WIN32 1
#define ZEND_DEBUG 0

#include <php.h>

#pragma comment(lib, "php5.lib")

After our build we get a match

 5

We can now  drop this in our extension directory.

Running phpInfo() will produce:

6

Running our script:

7

Success.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s