custom PHP extension - php

I need to create custom extension for PHP. All things are going well till I want to load compiled extension into PHP. Than I'm getting this error message (by using php -m): "Warning: PHP Startup: Invalid library (maybe not a PHP library) 'first.so' in Unknown on line 0"
OS:
OS X 10.8.5
Here is my compiling process thru which there is no error at all :
$ phpize54
$ sudo ./configure --with-php-config=/opt/local/bin/php-config54
$ sudo make install
I'm registering the extension by .ini file in dir for additional .ini files
extension=first.so
I'm using no another additional tools. Whan I was trying to comtile some extension right from the extensions included in sources of PHP distribution (posix, to be concrete) in this way, everything works and extension was loaded correctly.
Does anybody see any mistake in my source code below? Thank U for hellp.
config.m4:
PHP_ARG_ENABLE(first,whether to enable FIRST functions,
[ --disable-first Disable FIRST functions], yes)
if test "$PHP_FIRST" = "yes"; then
AC_DEFINE(HAVE_FIRST, 1, [whether to include FIRST functions])
PHP_NEW_EXTENSION(first, first.c, $ext_shared)
fi
first.c
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "ext/standard/info.h"
extern zend_module_entry first_module_entry;
#define first_module_ptr &first_module_entry
#define phpext_first_ptr first_module_ptr
static PHP_MINFO_FUNCTION(first)
{
php_info_print_table_start();
php_info_print_table_row(2, "Revision", "$Id: 01 $");
php_info_print_table_end();
}
static PHP_MINIT_FUNCTION(first)
{
return SUCCESS;
}
PHP_FUNCTION(hallo)
{
RETURN_STRING("FIRST extension function works\n", 1);
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_hallo, 0, 0, 0)
ZEND_END_ARG_INFO()
const zend_function_entry first_functions[] =
{
PHP_FE(hallo, arginfo_hallo)
PHP_FE_END
};
zend_module_entry first_module_entry = {
STANDARD_MODULE_HEADER,
"first",
first_functions,
PHP_MINIT(first),
NULL,
NULL,
NULL,
PHP_MINFO(first),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_POSIX
ZEND_GET_MODULE(first)
#endif

#ifdef COMPILE_DL_POSIX
ZEND_GET_MODULE(first)
#endif
This looks wrong. In config.m4 you claim your extension is called first (PHP_NEW_EXTENSION(first, ...) but there you are checking whether an extension called posix is built shared.
Background: PHP can load extensions (meaning PHP modules not to be confused with Zend Extensions like xdebug or opcache - they are a different topi) in two ways. Either statically compiled into PHP or shared.
Statically means that your extension is built as part of PHP and built right in the php binary. (put it in php-src/ext/, run buildconf, configure) This works by configure creating a file main/internal_functions.c which includes all php_foo.h files and creating an array of module_entry which is processed at PHP start.
If an extension is build shared (using --with-foo=shared in php-src or phpize) and loading it via php.ini PHP will look for a function get_module() using dlopen() and dlsym() system apis (or LoadDll on Windows) which will return the module structure. In order to not habe to write that function get_module() all the time the macro ZEND_GET_MODULE does that. But get_module is a common name, and during a static build it has to be prevented that each extension creates it as that would cause a conflict to have the same function multiple times in the same binary, that's why the build system creates COMPILED_DL_FOO defines which can be used as guards.
So in your case PHP opens the library, looks for a get_module() but can't find it, shrugs and reports an error.
References:
http://lxr.php.net/xref/PHP_TRUNK/ext/standard/dl.c#100 - PHP's module loading routine
http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_API.h#135 - ZEND_GET_MODULE
The config.h file in your tree after running configure (search for COMPILE_DL there)

Related

mb_detect_encoding() missing in PHP?

Using PHP 5.6.13 Windows CLI from http://windows.php.net/download#php-5.5, this:
include 'simple_html_dom.php'; //V1.5
$html = file_get_html('http://google.com');
fails with
Call to undefined function mb_detect_encoding()
and SO suggests this is due to the multibyte string extension missing. Indeed phpinfo() says
Zend Multibyte Support => disabled
which is is a surprise and disappointment.
What's the remedy? I want to remain with an official build.
The build package from windows.php.net contains everything you need to run the mbstring extension; it's just not enabled by default.
use <?php echo get_cfg_var('cfg_file_path'); to check which php.ini you have to edit
make sure the extension_dir=... directive points to the {yourPHPDir}/ext directory
add or uncomment* the line extension=php_mbstring.dll
(if php runs as a httpd module: restart the webserver; not the case here)
*) any line starting with a ; or (before php 7) # is concidered a comment.

PHP Extension for C is failing to find function in C Library

Problem
I am learning to create a php extension. I have created a php extension for a basic hello world app. But the moment I try to include functions from the C library I am trying to entend then I get the following error message:
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20121212/hello.so' - /usr/lib/php5/20121212/hello.so: undefined symbol: nc_open in Unknown on line 0
This nc_open() function is the key function in the libary I am trying to extend
Process
I have created by header and config files and my c extension file which contains:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_hello.h"
#include <netcdf.h>
...
PHP_FUNCTION(hello_world)
{
int status;
int ncid;
status = nc_open("sample.nc", 0, &ncid);
RETURN_LONG(status);
}
I have set up a directory (on Ubuntu) and run the phpize and configure steps. I run the make command which runs with no errors.
In my php.ini file I have the hello.so extension which points to symbolic link to the file I make.
I then restart the apache server on my local machine and then run:
php -r 'echo hello_world();'
and get:
- /usr/lib/php5/20121212/hello.so: undefined symbol: nc_open in Unknown on line 0
PHP Warning: Module 'xdebug' already loaded in Unknown on line 0
PHP Fatal error: Call to undefined function hello_world() in Command line code on line 1
PHP Stack trace:
PHP 1. {main}() Command line code:0
The error only occurs when I have a function from netcdf.h
The error does not occur from just having the include statement.
What I've tried:
Firstly I tried writing a basic c program to check that it would work, I managed to succeed by compiling it with:
gcc test.c -lnetcdf -o Test
and running ./Test
I tried using the following MakeFile
LDLIBS = -lnetcdf
but was unsuccessful.
What I would like:
Preferably to know how to get this library to work in my extension but I would settle for being pointed to documents or examples to help me understand what I need to know to accomplish this.
Update
Following Elliott Frisch's comments I have tried the
Setting the PHP_RPATHS=/usr/local
Setting /etc/ld.so.conf to:
include /etc/ld.so.conf.d/*.conf
/usr/lib
Changing the MakeFile to:
LDLIBS = -lnetcdf
LDFLAGS = -static
I am making the assumption that /usr/local is the correct directory due to it containing netcdf.so
I have added the following lines to my config.m4 file according to try adding the suggested functions
PHP_ADD_INCLUDE(/usr/lib)
PHP_ADD_LIBRARY_WITH_PATH(netcdf, /usr/lib, HELLO_SHARED_LIBADD)
Unfortunately I am still getting the problem so I am trying to understand what these functions mean to make sure I using them correctly. (The library I need to connect to is /usr/lib/libnetcdf.a and need to include netcdf.h from that file.)
You'll need to use PHP_ADD_LIBRARY_WITH_PATH & PHP_ADD_INCLUDE macros in config.m4 to handle linking. Autoconf's macros are also helpful for find & verifying existing libraries.
The best examples can be found in the ext directory of PHP's source code. Like ext/zlib
PHP_ADD_LIBPATH($ZLIB_DIR/$PHP_LIBDIR, ZLIB_SHARED_LIBADD)
PHP_ZLIB_DIR=$ZLIB_DIR
PHP_ADD_LIBRARY(z,, ZLIB_SHARED_LIBADD)
PHP_ADD_INCLUDE($ZLIB_INCDIR)
And more detailed examples in ext/oracle (from apple's open source labs)
PHP_ADD_LIBRARY(clntsh, 1, ORACLE_SHARED_LIBADD)
PHP_ADD_LIBPATH($ORACLE_DIR/lib, ORACLE_SHARED_LIBADD)
The issue was with an incorrectly configured config.m4 file.
I added the following that I modified from examples I found to get it to work:
if test "$PHP_HELLO" != "no"; then
SEARCH_PATH="/usr/local /usr" # you might want to change this
SEARCH_FOR="/include/netcdf.h" # you most likely want to change this
if test -r $PHP_HELLO/$SEARCH_FOR; then # path given as parameter
HELLO_INC_DIR=$PHP_HELLO/include
else # search default path list
AC_MSG_CHECKING([for netcdf.h in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
HELLO_INC_DIR=$i/include
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$HELLO_INC_DIR"; then
AC_MSG_RESULT([not found])
fi
SEARCH_PATH="/usr/local /usr" # you might want to change this
SEARCH_FOR="/lib/libnetcdf.a" # you most likely want to change this
if test -r $PHP_HELLO/$SEARCH_FOR; then # path given as parameter
HELLO_LIB_DIR=$PHP_HELLO/lib
else # search default path list
AC_MSG_CHECKING([for libnetcdf in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
HELLO_LIB_DIR=$i/lib
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$HELLO_LIB_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please check the netCDF distribution])
fi
# --with-netcdf -> add include path
PHP_ADD_INCLUDE($HELLO_INC_DIR)
# --with-netcdf -> check for lib and symbol presence
LIBNAME=netcdf # you may want to change this
dnl O_LDFLAGS=$LDFLAGS
dnl LDFLAGS="$LDFLAGS -L$NETCDF_LIB_DIR -l$LIBNAME"
PHP_ADD_LIBRARY($LIBNAME)
LIBSYMBOL=nc_inq_libvers # you most likely want to change this
PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
[
PHP_ADD_LIBRARY($LIBNAME)
AC_DEFINE(HAVE_HELLO,1,[Build netCDF extension])
],[
AC_MSG_ERROR([wrong netCDF library version or lib not found])
])
PHP_SUBST(HELLO_SHARED_LIBADD)
HELLO_SHARED_LIBADD=-l$LIBNAME

WSO2 WSF/PHP installation problems (C devs help needed)

I'm trying to install WSO2 WSF/PHP extension to use SOAP with WSSE.
I was having problems when I was compiling sources, I needed to checkout trunk (instead of tag 2.1) from their repository, couple of times I fixed php 5.4 compatibility issues in source codes, finally everything compiled successfully
But when I try to enable this extension I get an error:
user#centos:~/wsf$ php -i | grep "wsf"
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20100525+lfs/wsf.so' - /usr/lib/php5/20100525+lfs/wsf.so: undefined symbol: rampart_context_set_prv_key in Unknown on line 0
/etc/php5/cli/conf.d/20-wsf.ini,
PWD => /home/user/wsf
_SERVER["PWD"] => /home/user/wsf
I did grep on sources and found this:
user#centos:~/wsf$ grep -r "rampart_context_set_prv_key" .
./src/.svn/text-base/wsf_policy.c.svn-base: rampart_context_set_prv_key(rampart_context, env, Z_STRVAL_PP(token_val));
./src/.svn/text-base/wsf_policy.c.svn-base: if (rampart_context_set_prv_key_type (rampart_context, env, AXIS2_KEY_TYPE_PEM) == AXIS2_SUCCESS)
Binary file ./src/modules/wsf.so matches
./src/wsf_policy.c: rampart_context_set_prv_key(rampart_context, env, Z_STRVAL_PP(token_val));
./src/wsf_policy.c: if (rampart_context_set_prv_key_type (rampart_context, env, AXIS2_KEY_TYPE_PEM) == AXIS2_SUCCESS)
Binary file ./src/.libs/wsf.soT matches
Binary file ./src/.libs/wsf.so matches
Binary file ./src/.libs/wsf_policy.o matches
Binary file ./wsf_c/rampartc/src/util/.libs/librampart.so.0 matches
Binary file ./wsf_c/rampartc/src/util/.libs/librampart.a matches
Binary file ./wsf_c/rampartc/src/util/.libs/librampart.so.0.3.0 matches
Binary file ./wsf_c/rampartc/src/util/.libs/rampart_context.o matches
Binary file ./wsf_c/rampartc/src/util/.libs/librampart.so matches
./wsf_c/rampartc/src/util/rampart_context.c:rampart_context_set_prv_key(rampart_context_t *rampart_context,
./wsf_c/rampartc/src/util/rampart_context.c:rampart_context_set_prv_key_type(rampart_context_t *rampart_context,
./wsf_c/rampartc/src/util/rampart_context.c:rampart_context_set_prv_key_password(rampart_context_t *rampart_context,
Binary file ./wsf_c/rampartc/src/util/rampart_context.o matches
./wsf_c/rampartc/include/rampart_context.h: rampart_context_set_prv_key(rampart_context_t *rampart_context,
./wsf_c/rampartc/include/rampart_context.h: rampart_context_set_prv_key_type(rampart_context_t *rampart_context,
./wsf_c/rampartc/include/rampart_context.h: rampart_context_set_prv_key_password(rampart_context_t *rampart_context,
So basically I found only 1 file, wsf_policy.c which uses rampart_context_set_prv_key, but includes looks correct, and I don't know how to solve it. Any ideas?
Same Problem. Solved in the same way as in Error when trying to run security examples in wsf/php 2.1:
sudo apt-get install gcc-4.4
and then configuring wsf/php by running
./configure CC=gcc-4.4
Follow the rest of the normal installation steps and it should work.
You can also check the wsf.so library to see if it has the rampart libs linked in it by doing
ldd /usr/lib/php5/20090626/wsf.so
Also, just in case you haven't found it yet, here are the steps to compile WSF using PHP 5.4
https://wso2.org/jira/browse/WSFPHP-477
In my installation, the symbol "rampart_context_set_prv_key" is defined in the library ${wsf.home}/lib/librampart.so which is directly accessible from wsf.so thank to RPATH variable.

Can't get DocBlox to work with Netbeans

I'm trying to get Netbeans for Mac to integrate with DocBlox for documentation generation. I followed the instructions on the docblox site for integrating with netbeans, but when I actually try to generate documentation I get no output, and the following appears in the output window:
DocBlox version 0.17.2
PHP Warning: mkdir(): Permission denied in /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php on line 120
PHP Stack trace:
PHP 1. {main}() /usr/local/php5-20111115-115202/bin/docblox:0
PHP 2. DocBlox_Task_Project_Run->execute() /usr/local/php5-20111115-115202/bin/docblox:55
PHP 3. DocBlox_Task_Project_Parse->execute() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Run.php:141
PHP 4. DocBlox_Task_Project_Parse->getTarget() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php:270
PHP 5. mkdir() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php:120
Warning: mkdir(): Permission denied in /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php on line 120
Call Stack:
0.0004 655768 1. {main}() /usr/local/php5-20111115-115202/bin/docblox:0
0.0227 3376320 2. DocBlox_Task_Project_Run->execute() /usr/local/php5-20111115-115202/bin/docblox:55
0.0246 3538264 3. DocBlox_Task_Project_Parse->execute() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Run.php:141
0.0546 3867832 4. DocBlox_Task_Project_Parse->getTarget() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php:270
0.0546 3868056 5. mkdir() /usr/local/php5-20111115-115202/lib/php/DocBlox/src/DocBlox/Task/Project/Parse.php:120
ERROR: The given location "Reefknot" is not a folder
DocBlox creates documentation from PHP source files. The simplest way to use it is:
$ docblox run -d <directory to parse> -t <output directory>
This will parse every file ending with .php, .php3 and .phtml in <directory to parse> and then
output a HTML site containing easily readable documentation in <output directory>.
DocBlox will try to look for a docblox.dist.xml or docblox.xml file in your current working directory
and use that to override the default settings if present. In the configuration file can you specify the
same settings (and more) as the command line provides.
Usage:
docblox project:run [options]
-h [--help] Show this help message
-q [--quiet] Silences the output and logging
-c [--config] [STRING] Configuration filename OR "none", when this option is omitted DocBlox tries to load the docblox.xml or docblox.dist.xml from the current working directory
-f [--filename] STRING Comma-separated list of files to parse. The wildcards ? and * are supported
-d [--directory] STRING Comma-separated list of directories to (recursively) parse.
-t [--target] [STRING] Path where to store the generated output (optional, defaults to "output")
-e [--extensions] [STRING] Optional comma-separated list of extensions to parse, defaults to php, php3 and phtml
-i [--ignore] [STRING] Comma-separated list of file(s) and directories that will be ignored. Wildcards * and ? are supported
-m [--markers] [STRING] Comma-separated list of markers/tags to filter, (optional, defaults to: "TODO,FIXME")
-v [--verbose] Provides additional information during parsing, usually only needed for debugging purposes
--title [STRING] Sets the title for this project; default is the DocBlox logo
--template [STRING] Sets the template to use when generating the output
--force Forces a full build of the documentation, does not increment existing documentation
--validate Validates every processed file using PHP Lint, costs a lot of performance
--parseprivate Whether to parse DocBlocks tagged with #internal
--visibility [STRING] Specifies the parse visibility that should be displayed in the documentation (comma seperated e.g. "public,protected")
--defaultpackagename [STRING] name to use for the default package. If not specified, uses "default"
--sourcecode Whether to include syntax highlighted source code
-p [--progressbar] Whether to show a progress bar; will automatically quiet logging to stdout
I have chmoded the target directory to 0777, but still no joy.
Has anybody got any ideas what's going wrong here? I'm running OSX Lion, Netbeans 7.1RC2 and DocBlox 0.17.2 installed via PEAR
Short version
it appears you need to modify the phpdoc batch file of NetBeans as described here: https://github.com/docblox/docblox/issues/195
Explanation
the problem is probably caused by Netbeans passing a title using the shortcut notation (-ti) of phpDocumentor. I am assuming your project is called Reefknot and Netbeans tries to add -ti Reefknot as last argument.
Since DocBlox is unable to handle the double character shortcut notation it will interpret -ti as being -t and as such cause Docblox to try and write to a folder 'Reefknot'.

Compiling PHP Extension with correct API Version on Windows

I have finally created a very simple "Hello World" style PHP Extension dll on windows, after immeasurable hassle. However, although I have successfully created a DLL, and put it in the extensions folder, and told php.ini about it, now I get this:
PHP Warning: PHP Startup: \x81\xc2\xc0\x03L&\xc0\x03: Unable to initialize module\nModule compiled with module API=16777522\nPHP compiled with module API=20090626\nThese options need to match\n in Unknown on line 0
Warning: PHP Startup: ÂÀL&À: Unable to initialize module
Module compiled with module API=16777522
PHP compiled with module API=20090626
These options need to match
in Unknown on line 0
It seems that my PHP_API_VERSION is 20090626, but for some reason my DLL thinks it's PHP_API_VERSION is 16777522.
The tutorial below was some help in compiling an extension dll:
http://www.talkphp.com/vbarticles.php?do=article&articleid=49&title=creating-custom-php-extensions
Having written it myself, I have access to all of the source code for the php extension in question - But, where is it that I control the PHP_API_VERSION that ends up in the DLL?
I am compiling the dll successfully with Borland C++ Builder v5.5, not Visual Studio.
Here is the complete source, in case it matters:
// Needed to make following two #includes compatible with borland header files
void __fastcall __assume(int t) {
return;
}
typedef unsigned int socklen_t;
typedef enum BOOL
{
false=0,
true
} bool;
// end Borland compatibility code
#include "php.h"
#include "zend_config.w32.h"
ZEND_FUNCTION(fetch_LinkGrammar_links);
zend_function_entry LinkGrammar_ext_functions[] = {
ZEND_FE(fetch_LinkGrammar_links, NULL)
{NULL, NULL, NULL}
};
zend_module_entry LinkGrammar_ext_module_entry = {
STANDARD_MODULE_HEADER,
"LinkGrammar Extension",
LinkGrammar_ext_functions,
NULL, NULL, NULL, NULL, NULL,
"1.0",
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(LinkGrammar_ext);
ZEND_FUNCTION(fetch_LinkGrammar_links)
{
bool World = false;
char *RetVal= "";
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &World) == FAILURE)
{
RETURN_STRING("Missing Parameter", true);
}
if (World == true)
{
RetVal= "Hello World";
}
else
{
RetVal= "Hello";
}
RETURN_STRING(RetVal, true);
}
What can I change to eliminate the PHP Startup Error that the API must match?
It turns out it was the "Data Alignment" - My DLL was being compiled using "Word" alignment and it needed to be double-word.
Sounds like you're compiling against a different version of PHP than the one you're running.
Take a peek in php.h and look for #define PHP_API_VERSION -- that's what you're compiling against.
Is that the same version that's running on your server?
Check your include paths, locate file php.h and check that the version there matches php that you are running (running version is found if you check phpinfo() output).
You should change the API version in zend_modules.h to the API version which your PHP server indicates in phpinfo().
For example if the PHP Extension API in phpinfo() is 20090523, you should change the API number in zend_modules.h file to 20090523 and then rebuild your project.

Categories