设为首页 收藏本站
查看: 498|回复: 0

[经验分享] Creating a PHP Extension for Windows using Microsoft Visual C++ 2008

[复制链接]

尚未签到

发表于 2015-11-3 13:20:50 | 显示全部楼层 |阅读模式
  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
  View Screenshot
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
  View Screenshot
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
  Still in the Configuration Properties window, select Linker -> General -> Additional Library Directories and enter the path to your /dev directory - View Screenshot
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
  View Screenshot
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
  View Screenshot
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"  
  Then save the file. This will include the standard Zend Win32 and PHP headers that our extension needs.
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
  Then comment it out or delete it - View Screenshot - then save and close the file.
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);
}  
  Quite the chunk of code! If you have used C++ before, most of it should look familiar.
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"  
  We start our code with two comments describing what our code does. We then include our standard header stdafx.h file.

PHP Code:
ZEND_FUNCTION(fetch_talkphp_links);  
  This line tells the Zend Engine (aka, PHP) what functions to expect in our extension. In our case we only have the one function which will be called fetch_talkphp_links().

PHP Code:
zend_function_entry talkphp_ext_functions[] = {
   
ZEND_FE(fetch_talkphp_links, NULL)
    {
NULL, NULL, NULL}
};  
  This declares our Zend function block. We won't go into too much detail about this block here (save that for a future advanced tutorial!) but in general terms, it tells the Zend Engine about the functions in our extension.
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
};  
  This block of code tells the Zend engine all about our extension. Lets break this down line by line:

Code:
zend_module_entry talkphp_ext_module_entry = {
  This creates a structure of type zend_module_entry called talkphp_ext_module_entry.

Code:
STANDARD_MODULE_HEADER,
  This line actually looks for four parameters, size, zend_api, zend_debug and zts status. We use the Macro STANDARD_MODULE_HEADER to fill these in for us as a time saver.

Code:
"TalkPHP Extension",
  This is the name of our extension as we wish it to appear in phpinfo(). This can be anything you wish but should describe your extensions function, in this case, returning a link to TalkPHP.com.

Code:
talkphp_ext_functions,
  This line points to the Zend Function Block that we defined earlier in the code.

Code:
NULL, NULL, NULL, NULL, NULL,
  This is actually five lines condensed into one. The five lines are:

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);
  These allow you to define functions in your extension that will be run at specific times (eg, when the extension starts). We won't be using these in our TalkPHP extension so have set all five to NULL.

Code:
"1.0",
  This is the version number for our extension. If you do not wish to include a version then you can replace this with:

Code:
NO_VERSION_YET,
  And finally:

Code:
STANDARD_MODULE_PROPERTIES
};
  This uses the STANDARD_MODULE_PROPERTIES macro to fill in the rest of the structure then closes the structure block.
The next block of code:

Code:
ZEND_GET_MODULE(talkphp_ext);
  Tells the Zend engine that our extension is a dynamicly-loaded module, as opposed to being a module built-in to PHP. You will need this block for pretty much all of your PHP extensions.
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);
}  
  Creates the one and only function that we have in our PHP extension. Lets break this block of code down:

Code:
ZEND_FUNCTION(fetch_talkphp_links)
{
  This uses the function ZEND_FUNCTION to create a new PHP function called fetch_talkphp_links().

Code:
bool useHtml = false;
char *link = "";
  This creates two variables. The first, useHtml is a boolean variable that will tell our function whether it should wrap HTML <a href></a> tags around our TalkPHP.com link. By default, we set this to false.
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);
}
  This block of code fetches checks and fetches our functions parameters.
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
  So as you can see in our code, we use "|b", which means that we want an optional boolean value (ie, TRUE or FALSE), These values can be stacked together, so to accept a string, a boolean, and an optional long, you would use "sb|l".
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
  As you can see, our "Missing Parameter" error message isn't particularly descriptive and should be improved in your own PHP extensions.
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";
}
  This checks to see if the useHtml variable is set to TRUE, then puts our link to TalkPHP.com (with HTML formatting if requested) into the link variable.
And finally:

Code:
RETURN_STRING(link, true);
}
  We return a string to PHP, in this example, the link to TalkPHP.com.
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
  And finally, restart your web server to force PHP to load your new extension.
Now we need to make sure that our extension loaded correctly. Create a PHP script that runs phpinfo():

PHP Code:
<?php
phpinfo
();
  and run it in your web browser. You should see that your extension has been loaded in the Additional Modules section - View Screenshot
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 />";
  As you can see, we call our custom function fetch_talkphp_links() twice. The first, without a parameter which should return a plain-text link, the second time, we provide a parameter that indicates that we want a HTML link to be returned.
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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-134556-1-1.html 上篇帖子: 空白密码引发远程连接Windows Server 2008失败 下篇帖子: 深入了解 Windows Server 2008 内核变化--内存管理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表