问题
The code I'm working on runs perfectly on Windows XP and on Mac OS X. When testing it on CentOS (and on Fedora and Ubuntu), it's not working properly. Searching the nets led me to the conclusion that it's the glibc
version of the iconv
that's causing the problem. So now I need the libiconv
version of iconv
for Zend Lucene to work properly.
I already downloaded libiconv and configured it with --prefix=/usr/local
, make
, then make install
without any errors. It seems that it was successfully installed because executing /usr/local/bin/iconv --version
says the version is the libiconv
. Although a simple iconv --version
still gives the glibc
version.
Then I recompiled PHP from source using --with-iconv=/usr/local
. But still, the phpinfo()
is showing the iconv
being used is the glibc
version. I've also already tried several other compiles using --with-iconv-dir
or using /usr/local/bin/php
.
Of course, I restarted the web server after recompiling PHP.
I have the following line in my /etc/httpd/conf/httpd.conf
:
LoadModule /usr/lib/httpd/modules/libphp5.so
and libphp5.so
is actually in /usr/lib/httpd/modules
.
phpinfo()
shows PHP 5.3.3. I also yum removed the pre-installed PHP 5.1.* just to make sure. But the iconv is still using the glibc version.
ldd /usr/lib/httpd/modules/libphp5.so
gives
linux-gate.so.1 => (0x003b1000)
/usr/local/lib/preloadable_libiconv.so (0x00110000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x001ed000)
librt.so.1 => /lib/librt.so.1 (0x0021f000)
libmysqlclient.so.15 => /usr/lib/mysql/libmysqlclient.so.15 (0x003b2000)
libldap-2.3.so.0 => /usr/lib/libldap-2.3.so.0 (0x0026e000)
liblber-2.3.so.0 => /usr/lib/liblber-2.3.so.0 (0x00370000)
libiconv.so.2 => /usr/local/lib/libiconv.so.2 (0x00516000)
libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x002a8000)
libpng12.so.0 => /usr/lib/libpng12.so.0 (0x00228000)
libz.so.1 => /usr/lib/libz.so.1 (0x00328000)
libcurl.so.3 => /usr/lib/libcurl.so.3 (0x00f23000)
libm.so.6 => /lib/libm.so.6 (0x0033b000)
libdl.so.2 => /lib/libdl.so.2 (0x00364000)
libnsl.so.1 => /lib/libnsl.so.1 (0x0037e000)
libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00f5f000)
libssl.so.6 => /lib/libssl.so.6 (0x0862c000)
libcrypto.so.6 => /lib/libcrypto.so.6 (0x04145000)
libgssapi_krb5.so.2 => /usr/lib/libgssapi_krb5.so.2 (0x08e2d000)
libkrb5.so.3 => /usr/lib/libkrb5.so.3 (0x0611a000)
libk5crypto.so.3 => /usr/lib/libk5crypto.so.3 (0x005f4000)
libcom_err.so.2 => /lib/libcom_err.so.2 (0x0024e000)
libidn.so.11 => /usr/lib/libidn.so.11 (0x071f5000)
libc.so.6 => /lib/libc.so.6 (0x08aa6000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00397000)
/lib/ld-linux.so.2 (0x00251000)
libresolv.so.2 => /lib/libresolv.so.2 (0x0748a000)
libsasl2.so.2 => /usr/lib/libsasl2.so.2 (0x07ddf000)
libkrb5support.so.0 => /usr/lib/libkrb5support.so.0 (0x062b7000)
libkeyutils.so.1 => /lib/libkeyutils.so.1 (0x00369000)
libselinux.so.1 => /lib/libselinux.so.1 (0x0913b000)
libsepol.so.1 => /lib/libsepol.so.1 (0x07eb4000)
This is a cross-post from: NullPointer.ph
回答1:
I just have changed my php-5.3.3 from glibc's iconv to GNU libiconv through the manual recompiling of the php iconv extension. Follow these steps:
- download php-5.3.3 source code package
- extract it and go into
php-5.3.3/ext/iconv
subdirectory - execute
phpize
command (if you have no such command then installphp-devel
package) (*) edit configure file (
vim configure
): addiconv_impl_name=""
at 4664 line (exact line number on your system configuration may be different):... iconv_impl_name="" if test -z "$iconv_impl_name"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if using GNU libiconv" >&5< ...
./configure --with-iconv=/usr/local|grep iconv
:checking if using GNU libiconv... yes
make
sudo make install
And now I run php -i|grep "iconv impl"
and got:
iconv implementation => libiconv
* This trick forces configure to select the GNU libiconv instead of glibc's iconv. By default it checks for glibc's iconv at first step and does not check for GNU libiconv at all.
回答2:
Your module (libphp5.so
) is linked to two shared libraries which are providing the same symbol (in this case the symbol is iconv
and the libraries are libiconv.so.2
and probably libc.so.6
).
When this happen, the first loaded symbol is used: probably libc.so.6
gets loaded before libiconv.so.2
and thus it's the one providing you with the iconv
symbol.
You can force the dynamic loader to load a library before any other; you can do this by setting the LD_PRELOAD
environment variable to the library you want to preload.
I'm not an expert about Apache, so I'm not totally sure about how it works, how it starts its process and what processes it uses, but I think that setting LD_PRELOAD
before running apache should do the trick:
LD_PRELOAD=/usr/local/lib/libiconv.so.2
A little example to show LD_PRELOAD
in action:
Will compile myfopen.c
as a shared library (myfopen.so
): it will provide a fopen
symbol (already defined in libc
):
$ cat myfopen.c
int fopen(const char *path, const char *mode){ return -1; }
$ gcc -o libmyfopen.so myfopen.c -shared
Compiling printfopen.c
as an executable (printfopen
) which just prints the result of fopen
; will link it against both libc
and libmyfopen
(LD_LIBRARY_PATH
is needed to let the linker look for the libraries also in .
):
$ cat printfopen.c
#include <stdio.h>
int main( ) {
printf( "%d\n", fopen("","") );
return 0;
}
$ gcc -o printfopen printfopen.c -L. -lmyfopen
$ LD_LIBRARY_PATH=. ldd printfopen
linux-gate.so.1 => (0xb779d000)
libmyfopen.so => ./libmyfopen.so (0xb779a000)
libc.so.6 => /lib/libc.so.6 (0xb762f000)
/lib/ld-linux.so.2 (0xb779e000)
Now I'm running it, to test if LD_PRELOAD
works:
$ LD_LIBRARY_PATH=. ./printfopen
-1
$ LD_PRELOAD=/lib/libc.so.6 LD_LIBRARY_PATH=. ./printfopen
0
$ LD_PRELOAD=libmyfopen.so LD_LIBRARY_PATH=. ./printfopen
-1
By default it loads libmyfopen
before libc
, then I tried to force loading libc
and then libmyfopen
first.
I guess that in your case libc
is getting loaded before libiconv
because the former is loaded by the application (apache?) before it loads the PHP module.
回答3:
Are you sure that LD_LIBRARY_PATH is set properly for httpd (web server) process? If not, try setting it like:
export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH}"
... in the script that starts the process (i.e. apachectl
).
The ldd
output you showed looks correct, but you invoked ldd
from user's environment, and httpd's might be different.
It could also help to set PATH to "/usr/local/bin:${PATH}", just in case.
回答4:
I understand, that this question is already answered and almost dead, but recently I tried to find a way to compile PHP with libiconv because in PHP I couldn't convert "∙" from UTF8 to CP1251 even with iconv //IGNORE. But I found another solution that worked for me without recompilation (just use //TRANSLIT):
iconv("UTF8", "CP1251//TRANSLIT//IGNORE", $text)
//TRANSLIT will transliterate ONLY unknown characters (not all, as some may guess), so it converts Russian 'ё', but transliterates unknown '∙' to 0x95 (which looks the same in the target charset).
回答5:
I do not know about CentOS, but in debian based distributions, like Ubuntu, you can choose the version of the program that you want to lauch defining the symbolic links at /etc/alternatives.
So, if you change the symbolink link /etc/alternatives/iconv in order to point to /usr/local/bin/iconv, this point forward it should use the correct version.
http://www.debian-administration.org/articles/91
来源:https://stackoverflow.com/questions/4743080/how-can-i-force-php-to-use-the-libiconv-version-of-iconv-instead-of-the-centos-i