PHP Extension using libtidy compiles, but does not load - php

I wrote an extension in C++ that uses libtidy, and it runs perfectly under PHP when I compile PHP --with-tidy.
However, it would be nice to have the extension run on a vanilla PHP. When I try to use the extension, I get something like:
PHP Warning:
PHP Startup:
Unable to load dynamic library 'extension.so':
undefined symbol: tidyCleanAndRepair in Unknown on line 0
and the extension is not loaded.
Obviously, the official tidy extension works fine. I have the relevant libtidy development packages installed on the system, and it compiles+links without a problem. I have tried to look through the code for the tidy extension, but it is a huge mass of macros - copying pieces at random felt like cargo code.
Besides linking to the library with PHP_ADD_LIBRARY_WITH_PATH(tidy, $TIDY_LIBDIR, TIDY_SHARED_LIBADD), Is there a PHP extension or C statement that fixes this error?
Thanks in advance!!
EDIT: here is the entire config.m4 file:
dnl config.m4 for extension htmlparser
PHP_ARG_ENABLE(htmlparse, whether to enable htmlparser support,
[ --enable-htmlparser Enable htmlparser support])
if test "$PHP_HTMLPARSER" != "no"; then
if test -r $PHP_LIBXML2/lib/libxml2.a; then
LIBXML2_DIR=$PHP_LIBXML2
else
AC_MSG_CHECKING(for libxml2 in default path)
for i in /usr/local /usr; do
if test -r $i/lib/libxml2.a; then
LIBXML2_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
if test -z "$LIBXML2_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the libxml2 distribution - libxml2.h should
be in <libxml2-dir>/include and libxml2.a should be in <libxml2- dir>/lib)
fi
PHP_ADD_INCLUDE($LIBXML2_DIR/include/libxml2)
PHP_ADD_LIBRARY_WITH_PATH(libxml2, $LIBXML2_DIR/lib, LIBXML2_SHARED_LIBADD)
AC_MSG_CHECKING(for boost in default path)
for i in /usr/local /usr; do
if test -r $i/include/boost; then
BOOST_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
if test -z "$BOOST_DIR"; then
AC_MSG_RESULT(not found)
AC_MSG_ERROR(Please reinstall the boost distribution!!!)
fi
PHP_ADD_INCLUDE($BOOST_DIR/include/boost/)
TIDY_SEARCH_DIRS="/usr/local /usr"
for i in $TIDY_SEARCH_DIRS; do
if test -f $i/include/tidy/tidy.h; then
TIDY_DIR=$i
TIDY_INCDIR=$i/include/tidy
elif test -f $i/include/tidy.h; then
TIDY_DIR=$i
TIDY_INCDIR=$i/include
fi
done
if test -z "$TIDY_DIR"; then
AC_MSG_ERROR(Cannot find libtidy)
fi
TIDY_LIBDIR=$TIDY_DIR/lib
PHP_ADD_INCLUDE($TIDY_INCDIR)
PHP_ADD_LIBRARY_WITH_PATH(tidy, $TIDY_LIBDIR, TIDY_SHARED_LIBADD)
PHP_CHECK_LIBRARY(tidy,tidyOptGetDoc,
[
AC_DEFINE(HAVE_TIDYOPTGETDOC,1,[ ])
],[],[])
AC_DEFINE(HAVE_HTMLPARSER, 1, [Whether you want htmlparser support])
PHP_SUBST(HTMLPARSER_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(stdc++, 1, HTMLPARSER_SHARED_LIBADD)
PHP_REQUIRE_CXX()
PHP_NEW_EXTENSION(htmlparser, php_htmlparser.cpp parsehtml.cpp StringBuilder.cpp, $ext_shared)
fi

did you compile your extension with the same php version as a vanilla php? you should use php sources with the same version.
besides, make sure that in php.ini file you loaded 'libtidy' extension before your extension.

Related

How to create an extension written in C ++ for PHP using static library

I'm writing an extension for PHP, I didn't have many problems creating the module, compiling, enabling it in Apache and putting the standard example to work.
I modified the default project (added a class with method and property, added information to be displayed in phpinfo, configured to accept c ++, configured the IDE CLion to build the project using commands in CMake) and still had no problems.
My difficulty started when I tried to really use my code, I created a static library (I did the unit tests with cunit, I went through valgrind without any problem) and I tried to use the extension and it doesn't work, I believe the problem is in the configuration of " config.m4 "
If I try to use PHP_CHECK_LIBRARY I get the error message:
./configure: line 4787: unset: `ac_cv_lib_nerd4ever-kaya-wrapper_fn_kaya_login': not a valid identifier
configure: error: wrong nerd4eve-kaya lib not found
If I directly included the library the project compiles, but has error when trying to load:
PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
Error in apache when try include library directly
PHP Warning: PHP Startup: Unable to load dynamic library 'kaya' (tried: /usr/lib/php/20180731/kaya (/usr/lib/php/20180731/kaya: cannot open shared object file: No such file or directory), /usr/lib/php/20180731/kaya.so (/usr/lib/php/20180731/kaya.so: undefined symbol: _ZN9nerd4ever4kaya9ExceptionD1Ev)) in Unknown on line 0
I try check the symbols in my library using the command "nm -C libnerd4ever-kaya-wrapper.a | less" and the fn_kaya_login is displayed
kaya_client.cc.o:
...
00000000 T fn_kaya_login
...
My config.m4
PHP_ARG_ENABLE(kaya, whether to enable kaya support,
[ --enable-kaya Enable kaya support], no)
if test "$PHP_KAYA" != "no"; then
PHP_ADD_INCLUDE(/usr/include)
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, KAYA_SHARED_LIBADD)
PHP_ADD_LIBRARY(jsoncpp, 1, KAYA_SHARED_LIBADD)
PHP_ADD_LIBRARY(curl, 1, KAYA_SHARED_LIBADD)
KAYA_BASE_DIR="$KAYA_DIR./../.."
AC_MSG_CHECKING(for kaya base dir)
if [ test -d "$KAYA_BASE_DIR" ]; then
dnl nerd4ever-kaya.a
KAYA_LIBRARY_PATH=`find $KAYA_BASE_DIR -type f -name "*nerd4ever-kaya-wrapper.a" | head -1 | xargs readlink -f | xargs dirname`
if [ test -z "$KAYA_LIBRARY_PATH" ]; then
AC_MSG_RESULT(["libs: not found"])
AC_MSG_ERROR(["static lib kaya is required"])
else
AC_MSG_RESULT(["libs kaya: ${KAYA_LIBRARY_PATH}"])
PHP_ADD_INCLUDE($KAYA_BASE_DIR/sources)
PHP_ADD_LIBPATH($KAYA_LIBRARY_PATH)
dnl PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
dnl PHP_CHECK_LIBRARY(nerd4ever-kaya-wrapper, fn_kaya_login,
dnl [
dnl PHP_ADD_LIBRARY(nerd4ever-kaya-wrapper, 1, KAYA_SHARED_LIBADD)
dnl AC_DEFINE(HAVE_KAYA, 1, [ Have kaya support ])
dnl ],[
dnl AC_MSG_ERROR([wrong nerd4eve-kaya lib not found])
dnl ],[
dnl -L$KAYA_LIBRARY_PATH -lnerd4ever-kaya-wrapper
dnl ])
dnl dnl PHP_ADD_LIBRARY_WITH_PATH(nerd4ever-kaya, KAYA_LIBRARY_PATH, EXTRA_LDFLAGS)
fi
fi
PHP_SUBST(KAYA_SHARED_LIBADD)
PHP_NEW_EXTENSION(kaya, php_kaya.cpp, $ext_shared,,)
fi

writing php extension that uses external shared library

I have difficulty trying to write a php extension that uses an external shared library:
The content of config.m4 is as follows:
PHP_ARG_WITH([foo],
[for foo support],
[AS_HELP_STRING([--with-foo],
[Include foo support])])
if test "$PHP_FOO" != "no"; then
PKG_CHECK_MODULES([LIBFREETYPE2], [freetype2 >= 23.4.17])
PHP_EVAL_INCLINE($LIBFREETYPE2_CFLAGS)
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi
The code of the main function in foo.c is as follows(Just a very simple example of using the external FreeType library):
PHP_FUNCTION(foo_test) {
ZEND_PARSE_PARAMETERS_NONE();
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
php_printf("FreeType library failed to load\n");
return;
}
php_printf("FreeType library successfully loaded\n");
FT_Done_Library(ft);
php_printf("FreeType library unloaded\n");
}
phpize, ./configure, make and make install all succeeded, and then I added the extension in php.ini:
extension = foo.so
So far so good, but then I ran the following command
echo "<?php foo_test();" | php
I got the following error message:
php: symbol lookup error: /the-path-of-foo/foo.so: undefined symbol:
FT_Init_FreeType
It looks like PHP doesn't load the external shared FreeType library my PHP extension intends to use.
How do I do to make PHP load the external shared FreeType library?
Thanks for help.
Resolved this issue by adding PHP_SUBST(FOO_SHARED_LIBADD) after PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD):
PHP_ARG_WITH([foo],
[for foo support],
[AS_HELP_STRING([--with-foo],
[Include foo support])])
if test "$PHP_FOO" != "no"; then
PKG_CHECK_MODULES([LIBFREETYPE2], [freetype2 >= 23.4.17])
PHP_EVAL_INCLINE($LIBFREETYPE2_CFLAGS)
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, FOO_SHARED_LIBADD)
PHP_SUBST(FOO_SHARED_LIBADD)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi
Your config.m4 shoud be like
...
PHP_EVAL_LIBLINE($LIBFREETYPE2_LIBS, EXTRA_CFLAGS)
PHP_SUBST(EXTRA_CFLAGS)
PHP_NEW_EXTENSION(foo, foo.c, $ext_shared)
fi

Getting "bson_decimal128_from_string" error trying to build mongo-php-driver

CentOS release 6.7 (centos-release-6-7.el6.centos.12.3.x86_64)
kernel 2.6.32-573.22.1.el6.x86_64
We had successfully built the mongo-php-driver with the instructions found here
Last week I spun up a new instance, patched it via yum update, and tried to build - and I'm consistently getting this error now:
>> make install
Installing shared extensions: /usr/lib64/php/modules/
>> service php-fpm restart
Stopping php-fpm: [ OK ]
Starting php-fpm: [12-Apr-2016 14:38:39] NOTICE: PHP message: PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/mongodb.so' - /usr/lib64/php/modules/mongodb.so: undefined symbol: bson_decimal128_from_string in Unknown on line 0
The build returns no errors, and seems to build the bson libraries as it goes:
checking for uint64_t... yes
... seen our uintptr_t in stdint.h (uint64_t too)
creating ./src/libbson/src/bson/bson-stdint.h : ___SRC_LIBBSON_SRC_BSON_BSON_STDINT_H
checking for int_least32_t... yes
checking for int_fast32_t... yes
..adding include stdint.h
... seen good stdint.h inttypes
... seen good uint64_t
... DONE ./src/libbson/src/bson/bson-stdint.h
* snip *
Build configuration:
CFLAGS : -g -O2
Extra CFLAGS : -pthread
Developers flags (slow) :
Code Coverage flags (extra slow) :
System mongoc : no
System libbson : no
LDFLAGS :
EXTRA_LDFLAGS :
MONGODB_SHARED_LIBADD : -lsasl2 -lssl -lcrypto -lrt
So far I have tried (and failed):
Deleting the mongodb.so file, repulling from github, and rebuilding
Descending into the src/libbson directory, building there, then
ascending and building again
Removing any packages containing bson (which include libbson and libbson-devel) using yum, in case it was building agains the wrong lib
My google-fu has failed me, and I can't find anything on SO about it. Anyone hit this kind of issue, or know a fix?

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

How can I link with a static C++ library with PHP?

I have a C++ library I would like to link to and use in PHP: libsigx.a
I would like to link with it by putting it in my config.m4 file (Zend).
[config.m4]
PHP_ARG_ENABLE(sigx,
[Whether to enable the "sigx" extension],
[ --enable-sigx Enable "sigx" extension support])
if test $PHP_SIGX != "no"; then
PHP_REQUIRE_CXX()
PHP_SUBST(SIGX_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, SIGX_SHARED_LIBADD)
PHP_ADD_LIBRARY(stdc++, 1, "libsigx.a")
PHP_NEW_EXTENSION(sigx, sigx.cc, $ext_shared)
fi
This is not working for me. I can run phpize and ./configure just fine, but when I go to run a test script, it complains about objects in the library not being available.
What I said in my comment worked.
PHP_ADD_LIBRARY_WITH_PATH(sigx, ., SIGX_SHARED_LIBADD)

Categories