We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

After upgrading from PHP5.5 to PHP5.5.1, an error occurs

When I start Apache now, I get:

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/phalcon.so' - /usr/lib64/php/modules/phalcon.so: undefined symbol: php_json_decode_ex in Unknown on line 0

This has only recently occurred after the upgrade.

Any thoughts?

New information: Downgrading to Phalcon 1.2.0 fixes the problem, even with PHP5.5.1 installed, leading me to believe it was never the difference in PHP version.

Thoughts?

@eBrian, you will need to recompile Phalcon after PHP upgrade.

The reason is that your PHP 5.0 version Phalcon was compiled against had json extension built-in and the new PHP 5.1 version does not have it.

Phalcon always tries to use the native functions when they are available (it is much faster to call a function directly than via PHP's userspace). However. these decisions are made during compile time and not run time.

Pretty interesting is that I don't see any references to php_json_decode_ex() in Phalcon's sources…

I had initially done a fresh install of PHP5.5 and installed Phalcon 1.2.0 and all was working well (on both my prod and dev servers). I thought upgrading to PHP5.5.1 (on my dev server) was what broke it, but, I upgraded my prod server (also running Phalcon 1.2.0) to PHP5.5.1 and it kept on chugging away. I then upgraded Phalcon to the latest (1.2.2 or 1.3.0, not sure) and that is when I got the error. Downgrading to Phalcon 1.2.0 fixed the problem.

Yes, 1.2.1 is where Phalcon started to use native JSON functions.

If you run this on your server with PHP 5.5.1:

php -m | grep json

what does it display?

It outputs: "json" on both my dev and prod servers.

OK, and what about

nm -g $(which php) | grep json

?

It outputs: "nm: /usr/bin/php: no symbols" on both my dev and prod servers.

Sorry, I gave you the wrong key — should have been

nm -D $(which php) | grep json

No output for that one.

Now could you please try to do the same for PHP 5.5.0?

I think you should see something like

00000000004d1a90 T php_json_decode_ex
00000000004d0170 T php_json_encode
edited Mar '14

Also, if your PHP shows configure command in phpinfo() or 'php -i', could you please post it for both 5.5.0 and 5.5.1?

It should look like this:

Build Date => May 12 2013 16:32:43
Configure Command =>  './configure'  '--build=x86_64-redhat-linux-gnu' '--host=x86_64-redhat-linux-gnu' '--target=x86_64-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib64' '--libexecdir=/usr/libexec' '--localstatedir=/var' '--sharedstatedir=/var/lib' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--cache-file=../config.cache' '--with-libdir=lib64' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--disable-debug' '--with-pic' '--disable-rpath' '--without-pear' '--with-bz2' '--with-exec-dir=/usr/bin' '--with-freetype-dir=/usr' '--with-png-dir=/usr' '--with-xpm-dir=/usr' '--enable-gd-native-ttf' '--with-t1lib=/usr' '--without-gdbm' '--with-gettext' '--with-gmp' '--with-iconv' '--with-jpeg-dir=/usr' '--with-openssl' '--with-pcre-regex' '--with-zlib' '--with-layout=GNU' '--enable-exif' '--enable-ftp' '--enable-magic-quotes' '--enable-sockets' '--with-kerberos' '--enable-ucd-snmp-hack' '--enable-shmop' '--enable-calendar' '--with-libxml-dir=/usr' '--enable-xml' '--with-system-tzdata' '--with-mhash' '--enable-force-cgi-redirect' '--libdir=/usr/lib64/php' '--enable-pcntl' '--with-imap=shared' '--with-imap-ssl' '--enable-mbstring=shared' '--enable-mbregex' '--with-gd=shared' '--enable-bcmath=shared' '--enable-dba=shared' '--with-db4=/usr' '--with-xmlrpc=shared' '--with-ldap=shared' '--with-ldap-sasl' '--enable-mysqlnd=shared' '--with-mysql=shared,mysqlnd' '--with-mysqli=shared,mysqlnd' '--enable-dom=shared' '--with-pgsql=shared' '--enable-wddx=shared' '--with-snmp=shared,/usr' '--enable-soap=shared' '--with-xsl=shared,/usr' '--enable-xmlreader=shared' '--enable-xmlwriter=shared' '--with-curl=shared,/usr' '--enable-fastcgi' '--enable-pdo=shared' '--with-pdo-odbc=shared,unixODBC,/usr' '--with-pdo-mysql=shared,mysqlnd' '--with-pdo-pgsql=shared,/usr' '--with-pdo-sqlite=shared,/usr' '--with-pdo-dblib=shared,/usr' '--with-sqlite3=shared,/usr' '--with-sqlite=shared,/usr' '--enable-json=shared' '--enable-zip=shared' '--without-readline' '--with-libedit' '--with-pspell=shared' '--enable-phar=shared' '--with-mcrypt=shared,/usr' '--with-tidy=shared,/usr' '--with-mssql=shared,/usr' '--enable-sysvmsg=shared' '--enable-sysvshm=shared' '--enable-sysvsem=shared' '--enable-posix=shared' '--with-unixODBC=shared,/usr' '--enable-fileinfo=shared' '--enable-intl=shared' '--with-icu-dir=/usr' '--with-enchant=shared,/usr' '--with-recode=shared,/usr'

I downgraded a virtual machine snapshot from my prod server to PHP5.5.0 but I didn't get the output you were expecting. Also, results from 'php -i' did not contain Configure Command (from both 5.5.0 and 5.5.1). I checked a PHP5.3 and 5.4 installation and it contained it, but I suppose that isn't relevant here..

Mmm OK. What distro do you use? I will try to reproduce the error locally.

One more thing: could you please chek whether JSON extension was loaded dynamically? Look for "json.so" in your PHP configuration. If it is loaded dynamically, please try to add "extension=phalcon.so" AFTER "extension=json.so".

Extensions Phalcon depends upon are:

  • json
  • pcre
  • session

They all have to be loaded before phalcon.

And if possible, could you please give the output of

objdump -p /path/to/phalcon.so

I use CentOS 6.4 for dev and prod.

I had extension=phalcon.so in /etc/php.ini and it wasn't working. I also tried putting extension=phalcon.so at the very end of the php.ini file but that didn't help it either. There are a series of .ini files in /etc/php.d/ that load extensions, one of which was json.ini. On a whim, I inserted extension=phalcon.so after extension=json.so in the json.ini file located in /etc/php.d and this resolved the problem. This seems like a bit of a hack though. I wonder if I create a file called, say, zzz.ini if that will be loaded after everything. Will report back soon.

Alright:

Creating /etc/php.d/zzzzz.ini with extension=phalcon.so solves the problem.

Creating /etc/php.d/aaaaa.ini with extension=phalcon.so brings back the problem.

I wonder if anybody else has ran into this? Perhaps it's a flaw of the CentOS PHP packaged distribution.

Please give me the output of

objdump -p /path/to/phalcon.so

I suspect that "-Wl,-z -Wl,now" slipped into compiler / linker options. This flag forces the dynamic linker to attaempt to resolve all undefined symbols when the shared library is loaded (and not to defer this until the sybmol is actually used). In this case if phalcon.so is loaded before json.so, 'php_json_decode_ex' symbol is not yet defined and linker complains loudly.

Did you build Phalcon yourself or used any third party repo?

edited Mar '14

Built it myself. Git clone and ./install method.

Here is the output:

[[email protected] php.d]# objdump -p /usr/lib64/php/modules/phalcon.so

/usr/lib64/php/modules/phalcon.so:     file format elf64-x86-64

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
         filesz 0x00000000002791a4 memsz 0x00000000002791a4 flags r-x
    LOAD off    0x00000000002791a8 vaddr 0x00000000004791a8 paddr 0x00000000004791a8 align 2**21
         filesz 0x0000000000039a20 memsz 0x0000000000042518 flags rw-
 DYNAMIC off    0x00000000002b2268 vaddr 0x00000000004b2268 paddr 0x00000000004b2268 align 2**3
         filesz 0x0000000000000190 memsz 0x0000000000000190 flags rw-
    NOTE off    0x0000000000000190 vaddr 0x0000000000000190 paddr 0x0000000000000190 align 2**2
         filesz 0x0000000000000024 memsz 0x0000000000000024 flags r--
EH_FRAME off    0x0000000000254e50 vaddr 0x0000000000254e50 paddr 0x0000000000254e50 align 2**2
         filesz 0x0000000000004ca4 memsz 0x0000000000004ca4 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**3
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-

Dynamic Section:
  NEEDED               libc.so.6
  SONAME               phalcon.so
  INIT                 0x0000000000038f48
  FINI                 0x0000000000239d78
  GNU_HASH             0x00000000000001b8
  STRTAB               0x0000000000001710
  SYMTAB               0x00000000000001f8
  STRSZ                0x0000000000001027
  SYMENT               0x0000000000000018
  PLTGOT               0x00000000004b24d0
  PLTRELSZ             0x0000000000001200
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000037d48
  RELA                 0x0000000000002930
  RELASZ               0x0000000000035418
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000002900
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000000002738
  RELACOUNT            0x0000000000002366

Version References:
  required from libc.so.6:
    0x0d696913 0x00 03 GLIBC_2.3
    0x09691a75 0x00 02 GLIBC_2.2.5

What repo do you use for the PHP 5.5.1? Webtatic, Remi, anything else?

Webtatic, yes.



1.2k
Accepted
answer

There is a patch in their .src.rpm called 'php-5.0.4-dlopen.patch'. You can blame it on for this :-)

--- php-5.0.4/Zend/zend.h.dlopen
+++ php-5.0.4/Zend/zend.h
@@ -102,11 +102,11 @@
 # endif

 # if defined(RTLD_GROUP) && defined(RTLD_WORLD) && defined(RTLD_PARENT)
-#  define DL_LOAD(libname)                     dlopen(libname, RTLD_LAZY | RTLD_GLOBAL | RTLD_GROUP | RTLD_WORLD | RTLD_PARENT)
+#  define DL_LOAD(libname)                     dlopen(libname, RTLD_NOW | RTLD_GLOBAL | RTLD_GROUP | RTLD_WORLD | RTLD_PARENT)
 # elif defined(RTLD_DEEPBIND)
-#  define DL_LOAD(libname)                     dlopen(libname, RTLD_LAZY | RTLD_GLOBAL | RTLD_DEEPBIND)
+#  define DL_LOAD(libname)                     dlopen(libname, RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND)
 # else
-#  define DL_LOAD(libname)                     dlopen(libname, RTLD_LAZY | RTLD_GLOBAL)
+#  define DL_LOAD(libname)                     dlopen(libname, RTLD_NOW | RTLD_GLOBAL)
 # endif
 # define DL_UNLOAD                                     dlclose
 # if defined(DLSYM_NEEDS_UNDERSCORE)

All it does is replaces RTLD_LAZY with RTLD_NOW.

See https://linux.die.net/man/3/dlopen

RTLD_LAZY Perform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced, then it is never resolved. (Lazy binding is only performed for function references; references to variables are always immediately bound when the library is loaded.) RTLD_NOW If this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty string, all undefined symbols in the library are resolved before dlopen() returns. If this cannot be done, an error is returned.

As you can see, the default PHP's behavior (RTLD_LAZY) allows to resolve the external symbols after all extensions have been loaded. The patch changes this behavior requesting that all symbols be resolvbed when the extension is loaded. And because of this patch the order of loaded extensions is important.

Unbelievable. I'm just going to load 3rd party extensions after everything using that zzzzz.ini located in /etc/php.d.

Very good work in spotting that. I appreciate you looking into this. It seems this issue case is fairly narrow in scope which is to say that only people using RHEL and Webtatic would face the issue.

Unbelievable+1 ... you are the man ...

Creating /etc/php.d/zzzzz.ini with extension=phalcon.so solves the problem. Creating /etc/php.d/aaaaa.ini with extension=phalcon.so brings back the problem

~ zzzzz.ini solved the problem because it is loaded after json.ini, you can try : add "extension=json.so" before "extension=phalcon.so" in your aaaaaa.ini and it's still work