我如何强制PHP使用iconv的libiconv版本而不是CentOS安装的glibc版本?

我正在使用的代码在Windows XP和Mac OS X上完美运行。在CentOS(以及Fedora和Ubuntu)上testing时,代码无法正常工作。 searchnetworking导致我得出的结论是,这是导致问题的iconvglibc版本。 所以现在我需要为Zend Lucene的iconvlibiconv版本正常工作。

我已经下载了libiconv并使用--prefix=/usr/local makeconfiguration, make ,然后make install没有任何错误的情况下make install 。 它似乎是成功安装,因为执行/usr/local/bin/iconv --version说版本是libiconv 。 虽然简单的iconv --version仍然给glibc版本。

然后,我使用--with-iconv=/usr/local从源代码重新编译了PHP。 但是, phpinfo()仍然显示正在使用的iconvglibc版本。 我也已经使用--with-iconv-dir或使用/usr/local/bin/php尝试了其他几个编译。

当然,我重新编译PHP后重新启动了Web服务器。

我在/etc/httpd/conf/httpd.conf有以下行:

 LoadModule /usr/lib/httpd/modules/libphp5.so 

libphp5.so实际上是在/usr/lib/httpd/modules

phpinfo()显示PHP 5.3.3。 我也yum删除了预先安装的PHP 5.1。*只是为了确保。 但iconv仍在使用glibc版本。

ldd /usr/lib/httpd/modules/libphp5.so给出

 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) 

这是一个交叉post: NullPointer.ph

Solutions Collecting From Web of "我如何强制PHP使用iconv的libiconv版本而不是CentOS安装的glibc版本?"

我只是通过手动重新编译php iconv扩展名,将我的php-5.3.3从glibc的iconv改为GNU libiconv。 按着这些次序:

  1. 下载php-5.3.3 源代码包
  2. 解压缩并进入php-5.3.3/ext/iconv子目录
  3. 执行phpize命令(如果你没有这个命令,然后安装php-devel包)
  4. (*)编辑配置文件( vim configure ):在4664行添加iconv_impl_name="" (系统配置上的确切行号可能不同):

     ... iconv_impl_name="" if test -z "$iconv_impl_name"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if using GNU libiconv" >&5< ... 
  5. ./configure --with-iconv=/usr/local|grep iconv

     checking if using GNU libiconv... yes 
  6. make

  7. sudo make install

现在我运行php -i|grep "iconv impl" ,得到:

 iconv implementation => libiconv 

*这个技巧强制配置选择GNU libiconv而不是glibc的iconv。 默认情况下,它在第一步检查glibc的iconv,根本不检查GNU libiconv。

你的模块( libphp5.so )链接到两个提供相同符号的共享库(在这种情况下,符号是iconv ,库是libiconv.so.2 ,可能是libc.so.6 )。

发生这种情况时,会使用第一个加载的符号:可能libc.so.6libiconv.so.2之前加载,因此它是提供iconv符号的那个。

您可以强制动态加载器在其他任何之前加载库; 您可以通过将LD_PRELOAD环境变量设置为要预加载的库来完成此操作。

我不是一个关于Apache的专家,所以我不完全确定它是如何工作的,它是如何启动它的过程以及它使用什么过程的,但是我认为在运行apache之前设置LD_PRELOAD应该可以做到这一点:

 LD_PRELOAD=/usr/local/lib/libiconv.so.2 

显示LD_PRELOAD小示例:

myfopen.c编译为共享库( myfopen.so ):它将提供一个fopen符号(已经在libc定义):

 $ cat myfopen.c int fopen(const char *path, const char *mode){ return -1; } $ gcc -o libmyfopen.so myfopen.c -shared 

编译printfopen.c作为一个可执行文件( printfopen ),它只是打印fopen的结果; 将它与libclibmyfopen链接(需要LD_LIBRARY_PATH让链接器查找库中的库)。

 $ 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) 

现在我正在运行它来测试LD_PRELOAD工作:

 $ 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 

默认情况下,它会在libc之前加载libmyfopen ,然后尝试强制加载libc ,然后先加载libmyfopen

我想在你的情况下, libc是在libiconv之前加载的,因为前者在加载PHP模块之前由应用程序加载(apache?)。

你确定为httpd(web服务器)进程正确设置了LD_LIBRARY_PATH吗? 如果不是,请尝试设置它:

 export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH}" 

…在启动过程的脚本(即apachectl )中。

你显示的ldd输出看起来是正确的,但你从用户环境中调用了ldd ,而httpd的可能是不同的。

以防万一,这也可以帮助将PATH设置为“/ usr / local / bin:$ {PATH}”。

我明白,这个问题已经答案,几乎已经死了,但最近我试图找到一种方法来编译PHP与libiconv,因为在PHP中,我不能将“∙”从UTF8转换为CP1251甚至iconv // IGNORE。 但是,我发现了另一个解决方案,我没有重新编译(只使用// TRANSLIT):

iconv(“UTF8”,“CP1251 // TRANSLIT // IGNORE”,$ text)

// TRANSLIT将音译未知字符(不是所有的,因为有些人可能会猜到),所以它转换俄文'ё',但音译未知'∙'为0x95(在目标字符集看起来相同)。

我不知道CentOS,但在基于Debian的发行版(如Ubuntu)中,可以选择要在/ etc / alternatives中定义符号链接的程序版本。

所以,如果你为了指向/ usr / local / bin / iconv而改变symbolink链接/ etc / alternatives / iconv,这一点应该使用正确的版本。

http://www.debian-administration.org/articles/91