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

时间:2011-01-20 03:08:25

标签: php linux apache glibc iconv

我正在开发的代码在Windows XP和Mac OS X上运行完美。在CentOS(以及Fedora和Ubuntu)上进行测试时,它运行不正常。搜索网络后,我得出的结论是导致问题的glibc iconv版本。所以现在我需要libiconv版本的iconv让Zend Lucene正常工作。

我已经下载了libiconv,并使用--prefix=/usr/localmake,然后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)

这是来自:NullPointer.ph

的交叉帖子

5 个答案:

答案 0 :(得分:9)

您的模块(libphp5.so)链接到两个提供相同符号的共享库(在这种情况下,符号为iconv,库为libiconv.so.2,可能为{{1 }})。

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

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

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

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的结果;会将它与fopenlibc相关联(需要libmyfopen才能让链接器在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 之前加载libmyfopen,然后我会尝试首先加载libc然后加载libc

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

答案 1 :(得分:9)

我刚刚通过手动重新编译php iconv扩展,将我的php-5.3.3从glibc的iconv改为GNU libiconv。请按照以下步骤操作:

  1. 下载php-5.3.3 source code
  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
  8. 现在我运行php -i|grep "iconv impl"并得到:

    iconv implementation => libiconv
    

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

答案 2 :(得分:0)

您确定为httpd(Web服务器)进程正确设置了LD_LIBRARY_PATH吗? 如果没有,请尝试将其设置为:

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

...在启动流程的脚本中(即apachectl)。

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

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

答案 3 :(得分:0)

我明白,这个问题已经回答并且几乎已经死了,但是最近我试图找到一种用libiconv编译PHP的方法因为在PHP中我无法将“∙”从UTF8转换为CP1251,即使用iconv // IGNORE也是如此。 但我找到了另一种解决方案,无需重新编译即可使用(只需使用// TRANSLIT):

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

// TRANSLIT将音译 ONLY 未知字符(并非全部,如某些人猜测的那样),因此它会转换俄语'ё',但将未知'∙'音译为0x95(在目标charset)。

答案 4 :(得分:-1)

我不了解CentOS,但是在基于debian的发行版中,比如Ubuntu,你可以选择你想在/ etc / alternatives中定义符号链接的程序版本。

因此,如果您更改符号链接/ etc / alternatives / iconv以指向/ usr / local / bin / iconv,则此点应该使用正确的版本。

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