writing php extension that uses external shared library - php

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

Related

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

Few function of ladybug debugger not working in symfony2 php app

I am using this
https://github.com/raulfraile/LadybugBundle
They have three functions
ld($var1[, $var2[, ...]]): shortcut for ladybug_dump
ldd($var1[, $var2[, ...]]): shortcut for ladybug_dump_die
ldr($format, $var1[, $var2[, ...]]): shortcut for ladybug_return
First two are working but for third it says undefined function
Also i tried this to dump json then i also get error
ld(json_decode($jsonContent, true));
and i get this
UndefinedFunctionException: Attempted to call function "bccomp" from
namespace "Ladybug\Type" in
/var/www/html/site/Symfony/vendor/raulfraile/ladybug/src/Ladybug/Type/FloatType.php
line 115
The bccomp() function needs the php BC Math extension.
These functions are only available if PHP was configured with
--enable-bcmath .
The Windows version of PHP has built-in support for this extension
Check php -i | grep -i bcmath ...
There should be a line ...
BCMath support => enabled
... if the extension is enabled. Otherwise you'll probably need to recompile php with --enable-bcmath.

Class 'PharData' not found

I get this error on my production server (CentOS 5.4 and php 5.3.5) :
Warning: include_once(PharData.php): failed to open stream: No such
file or directory in /var/www/ZendFramework/library/Zend/Loader.php on
line 146
Warning: include_once(): Failed opening 'PharData.php' for inclusion
(include_path='/var/www/fw:/var/www/vmms:/var/www/ZendFw/library:.:/usr/share/pear:/usr/share/php')
in /var/www/ZendFw/library/Zend/Loader.php on line 146
Fatal error: Class 'PharData' not found in
/var/www/vm/app/Backup.php on line 40
And this is the code which fail :
$phar = new PharData($imageBackupFile);
$phar->buildFromDirectory($imageDir);
Logger::info("Image directory backed up to: $imageBackupFile");
This code is working fine on my own computer.
PharData should be included by default in php 5.3+ ...
Thanks for your help!
UPDATE :
I am using the Zend Auto loader feature to load the good php files using this code :
require_once("Zend/Loader/Autoloader.php");
$autoloader = Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);
Zend autoloader is doing the include_once(PharData.php).
Just because Phar is bundled by default in PHP 5.3 doesn't mean that it's necessarily included in your install. When you build PHP with ./configure, you can pass the --disable-phar to disable the Phar extension.
To confirm this, run the following script:
<?php
phpinfo();
?>
One of the first sections to appear will be the Configure Command section. Review this section to see if the --disable-phar switch is present, and if there is a Phar section to the page in general.
If it's not present, you'll need to contact your host to have it enabled. There's a decent chance, however, that they won't do it for you since it could impact other users depending on how their servers are set up. If this is on your own machine, you'll need to either rebuild PHP without that switch, or install Phar manually from PECL (no idea if this would still work in 5.3, but I don't see why it wouldn't).

PHP: "independent" function to replace mime_content_type?

Is there any available, "independent" function which could replace mime_content_type()?
On my new hosting I'm getting error:
Fatal error: Call to undefined function mime_content_type() in download.php on line 3
finfo_file doesn't work as well...
Just mimic the function in your compat.php if you have one
if(!function_exists("mime_content_type"))
{
function mime_content_type($file)
{
$open_bit = finfo_open(FILEINFO_MIME_TYPE);
return finfo_file($open_bit, $file);
}
}
The above function (FileInfo) is a PECL extension and is encouraged by PHP To use as an alternative, if you do not have the extension installed you can do the following:
Find the url to the latest version of fileinfo from http://pecl.php.net/package/Fileinfo
Download, compile and install
Run the following commands
wget http://pecl.php.net/get/Fileinfo-X.X.X.tgz
gunzip Fileinfo-X.X.X.tgz
tar -xvf Fileinfo-X.X.X.tar
cd fileinfo-X.X.X
./configure
make
make install
Enable the extension by adding extension=fileinfo.so to your php.ini
Restart your web server and it should be working.
And then proceed as normal
As a matter of fact, there are two indepent implementations. One in http://upgradephp.berlios.de/ and one in PHP_Compat. You need the mime-magic file in either case.

PHP Extension using libtidy compiles, but does not load

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.

Categories