Introduction
PHP is built on extensions. For example, BC math, COM and Curl are all extensions to PHP. This article will show you how to create your very own Windows PHP extensions using Microsoft Visual C++ 2008 Express and Windows.
By the end of this article you should have a full fledged working PHP extension running on Windows!
Our PHP extension will be fairly simple. It will have one function, fetch_talkphp_links() which will return a link to TalkPHP.combut should give you a good start in creating your own extensions.
Requirements
Before we can start building our PHP extension, we need to install and setup our C++ compiler.
For this tutorial, we are going to use Microsoft Visual C++ 2008 Express. This is a full featured version of Microsoft Visual C++ 2008 that Microsoft offer as a free download.
To get started, visit Microsoft Visual C++ 2008 Express Downloads. This will run a web-based installer which will install (amongst other things) .Net Framework 3.5 and Visual C++ 2008.
The next thing we need is a working web server with PHP installed. There are many packages available which will automatically install Apache, PHP and MySQL on your Windows PC such as Wampserver.
The final item needed is a copy of the PHP source code. This must match the version of PHP that you have installed on your web server. For example, if you are running PHP v5.2.5, then you should download The PHP source for v5.2.5. Once downloaded, unzip it to its own folder.
Once all of the items above have been downloaded and installed, it's time to start setting up Microsoft Visual C++ 2008.
Step 1
Open Microsoft Visual C++ 2008 Express and create a new project by clicking File -> New -> Project or by clicking the shortcut button on the toolbar.
In the Project Types column, select Win32 then in the Templates box, select Win32 Project. Then enter a name for your new project then click ok. - View Screenshot
The Win32 Application Wizard will now appear. Click Next on the first screen, select DLL on the second, then click Finish - View Screenshot
This will create a default DLL application with a yourProjectName.cpp file and a standard header (stdafx.h) file.
Step 2
Next, we need to setup Microsoft Visual C++ with the Zend/PHP specific options so that it will know how to compile our new PHP extension.
Right-click on your project in the Solution Explorer and click on Properties - View Screenshot
Select Configuration Properties -> C/C++ -> General -> Additional Include Directories. This is where we will add the PHP headers and source files that our extension will need.
You need to add the following paths:
Note: Substitute the path below for the path to your PHP source
Code:
C:\Users\Alan\phpsource\php-5.2.5 C:\Users\Alan\phpsource\php-5.2.5\TSRM C:\Users\Alan\phpsource\php-5.2.5\Zend C:\Users\Alan\phpsource\php-5.2.5\regex C:\Users\Alan\phpsource\php-5.2.5\main
Now we need to add some Preprocessor Definitions to our project. Select Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions and add the following:
Code:
PHP_WIN32 ZEND_WIN32 ZTS=1 ZEND_DEBUG=0
The next step is to tell Microsoft Visual C++ where it can find the PHP libraries. These are usually located in the /dev folder in your PHP installation (note: this is your full PHP installation, not the PHP source code).
For example, if you where using Wampserver, the path may look something like:
Code:
C:\wamp\bin\php\php-5.2.5\dev
The next step is to tell Microsoft Visual C++ where to find the php5ts.lib library that our extension will need. To do this, select Configuration Properties -> Linker -> Input -> Additional Dependencies and add php5ts.lib to the box - View Screenshot
Compiling PHP extensions with Visual C++ 2008 can lead to problems so we need to add a command line switch to the linker which will resolve them for us. To do this, select Configuration Properties -> Linker -> Command Line and add the following to the input box:
Code:
/FORCE:MULTIPLE
And finally (yay!), we need to give our new PHP extension a filename. To do this, select Configuration Properties -> Linker -> General and change Output Filename to:
Code:
$(OutDir)\php_talkphp.dll
You can call your PHP extension anything you wish but to stick to conventions, we start it with php_ and since our extension will return a link to TalkPHP.com, it makes sense to call it php_talkphp.dll.
Writing our Extension
Now that we have Microsoft Visual C++ all setup and ready to go, it's time to start writing our extension.
Header Files
The first step is to edit the standard header file that was created for us. To do this, right-click on the filename in the - #include "stdafx.h" - directive and click Open Document - View Screenshot
Delete the contents of this file and replace it with the following:
PHP Code:
// talkphp_ext Header Files
#pragma once
// Include the Zend Win32 header and the general PHP header
#include "zend_config.w32.h"
#include "php.h"
At this point, we need to make a small adjustment to the file zend_config.w32.h to make it compatible with Microsoft Visual C++ 2008. To do this, right click on the filename in the line - #include "zend_config.w32.h" - and click Open Document
Scroll down and find the following line (around line 51):
Code:
#define vsnprintf _vsnprintf
The C++ Code
Now it is time to write the code that will make our extension do something useful.
I'm going to hit you with the full block of code first, then we'll go through it line by line to see how it all fits together.
talkphp_ext.cpp:
PHP Code:
// talkphp_ext
// PHP Extension for Windows that provides links to TalkPHP.com
#include "stdafx.h"
ZEND_FUNCTION(fetch_talkphp_links);
zend_function_entry talkphp_ext_functions[] = {
ZEND_FE(fetch_talkphp_links, NULL)
{NULL, NULL, NULL}
};
zend_module_entry talkphp_ext_module_entry = {
STANDARD_MODULE_HEADER,
"TalkPHP Extension",
talkphp_ext_functions,
NULL, NULL, NULL, NULL, NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(talkphp_ext);
ZEND_FUNCTION(fetch_talkphp_links)
{
bool useHtml = false;
char *link = "";
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &useHtml) == FAILURE)
{
RETURN_STRING("Missing Parameter", true);
}
if (useHtml == true)
{
link = "<a href=\"http://www.talkphp.com\">Visit TalkPHP.com!</a>";
}
else
{
link = "http://www.talkphp.com";
}
RETURN_STRING(link, true);
}
Now, lets break our code down to see what each bit does.
PHP Code:
// talkphp_ext
// PHP Extension for Windows that provides links to TalkPHP.com
#include "stdafx.h"
PHP Code:
ZEND_FUNCTION(fetch_talkphp_links);
PHP Code:
zend_function_entry talkphp_ext_functions[] = {
ZEND_FE(fetch_talkphp_links, NULL)
{NULL, NULL, NULL}
};
Note: This structure must end with {NULL, NULL, NULL} as this tells the Zend engine when the function list has ended.
PHP Code:
zend_module_entry talkphp_ext_module_entry = {
STANDARD_MODULE_HEADER,
"TalkPHP Extension",
talkphp_ext_functions,
NULL, NULL, NULL, NULL, NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
Code:
zend_module_entry talkphp_ext_module_entry = {
Code:
STANDARD_MODULE_HEADER,
Code:
"TalkPHP Extension",
Code:
talkphp_ext_functions,
Code:
NULL, NULL, NULL, NULL, NULL,
Code:
int (*module_startup_func)(INIT_FUNC_ARGS); int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); int (*request_startup_func)(INIT_FUNC_ARGS); int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
Code:
"1.0",
Code:
NO_VERSION_YET,
Code:
STANDARD_MODULE_PROPERTIES };
The next block of code:
Code:
ZEND_GET_MODULE(talkphp_ext);
The next block:
PHP Code:
ZEND_FUNCTION(fetch_talkphp_links)
{
bool useHtml = false;
char *link = "";
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &useHtml) == FAILURE)
{
RETURN_STRING("Missing Parameter", true);
}
if (useHtml == true)
{
link = "<a href=\"http://www.talkphp.com\">Visit TalkPHP.com!</a>";
}
else
{
link = "http://www.talkphp.com";
}
RETURN_STRING(link, true);
}
Code:
ZEND_FUNCTION(fetch_talkphp_links)
{
Code:
bool useHtml = false; char *link = "";
The second is a string that we will use to hold our link to TalkPHP.com.
Code:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &useHtml) == FAILURE)
{
RETURN_STRING("Missing Parameter", true);
}
The first part, ZEND_NUM_ARGS() TSRMLS_CC uses the zend_num_args() function and TSRMLS_CC macro to set the number of parameters that the zend_parse_parameters() function should parse.
The second part tells zend_parse_parameters() what types of parameters it should be expecting. You can use the following to specify the parameter types:
Code:
b = Boolean s = String l = Long d = Double (the following are all stored in a zval struct) a = Array o = Object of any class type O = Object of the specified class entry r = Resource z = zval Special identifier: | = Optional parameter
The final parameters to the zend_parse_parameters() function are the variable names that you want to store the parameters in. In our case, we want to store our Boolean value in the useHtml variable.
The rest is fairly straight forward, we use if() to check if the correct number and type of parameters where passed to our function, and if not (== FAILURE), we use the RETURN_STRING() function to give an error message.
For example, if we gave our fetch_talkphp_links function three parameters, we would get the following error:
Code:
Warning: fetch_talkphp_links() expects at most 1 parameter, 3 given in C:\wamp\www\talkphp_ext_test.php on line 11 Missing Parameter
If we didn't pass our fetch_talkphp_links() function any parameters then it would use the default (bool useHtml = false) as we specified that the one parameter we expect is optional.
The next block of code should look fairly familiar to any C/C++/PHP programmers:
Code:
if (useHtml == true)
{
link = "<a href=\"http://www.talkphp.com\">Visit TalkPHP.com!</a>";
}
else
{
link = "http://www.talkphp.com";
}
And finally:
Code:
RETURN_STRING(link, true); }
Compiling our Extension
Now that we have written our extension, it's time to compile and test it!
To do this, save all your extension files (.cpp and .h) then select Build -> Build Solution from the menu bar or use the F7 shortcut key.
Give it a few minutes and you should end up with something like the following:
View Screenshot
Don't worry about the Warnings, as long as you have 0 errors, all is well.
Note: If you do run into Errors when trying to build your extension, go back to the start of this article and double-check that all of the settings are correct in Microsoft Visual C++ 2008, in particular, the additional command line parameter for the Linker: /FORCE:MULTIPLE
Testing our Extension
Now that we have our extension built, we need to test it. To do this, browse to the folder where the extension .dll was created. By default, this is in C:\Users\<username>\Documents\Visual Studio 2008\Projects\<project name>\Debug - View Screenshot
Once you have found your new extension (in this case, php_talkphp.dll, you need to copy it to your PHP extensions folder. This is usually just called /ext under your main PHP folder.
For example, if you use Wampserver to setup PHP on Windows, this would likely be in C:\wamp\bin\php\php5.2.5\ext
Once copied, it should appear amongst your other PHP extensions - View Screenshot
We now need to edit the PHP.INI file to include our new extension. Open PHP.INI in a text editor and look for the Windows Extensions block then add your extension to the end of the list.
For example:
Code:
;extension=php_xmlrpc.dll ;extension=php_xsl.dll ;extension=php_zip.dll extension=php_talkphp.dll
Now we need to make sure that our extension loaded correctly. Create a PHP script that runs phpinfo():
PHP Code:
<?php
phpinfo();
If that has all worked successfully, then it is time to write a PHP script to test our extension:
PHP Code:
<?php
echo "Function Definition:<br />";
echo "string fetch_talkphp_links(bool \$useHtml)<br />";
echo "<hr />";
echo "Fetching plaintext link to TalkPHP using: fetch_talkphp_links();<br />";
echo fetch_talkphp_links() . "<br /><br />";
echo "Fetching HTML link to TalkPHP using: fetch_talkphp_links(true);<br />";
echo fetch_talkphp_links(true) . "<br />";
Run this script and you should see something like the following - View Screenshot
If it worked, congratulations! You have just created a full custom PHP extension for Windows! If it didn't, check your web servers log file for errors. It may be that you have to double-check the custom Microsoft Visual C++ settings that we did at the start of this article.
Conclusion
As you have seen, creating a custom PHP extension is fairly straight-forward. The only time consuming part in this article was downloading and setting up Microsoft Visual C++ 2008. Now that we've done that, we can jump straight in to coding our new extension.
"But wait! What about Linux extensions?" I hear you cry. Linux PHP extensions are created in much the same way as Windows ones. The C++ code is essentially the same, with just a few changes in the header files. Take a look at the some of the links below which will provide more information.
Links and Further Reading
http://uk.php.net/manual/en/internals2.php
An improved manual for writing PHP extensions


Join the friendly bunch on IRC...