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

Ran*_*ell 9 php linux apache glibc iconv

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

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

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

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

我的内容如下/etc/httpd/conf/httpd.conf:

LoadModule /usr/lib/httpd/modules/libphp5.so
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

这是一个交叉帖子:NullPointer.ph

peo*_*oro 9

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

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

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

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

LD_PRELOAD=/usr/local/lib/libiconv.so.2
Run Code Online (Sandbox Code Playgroud)

一个展示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
Run Code Online (Sandbox Code Playgroud)

编译printfopen.cprintfopen只打印结果的可执行文件()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)
Run Code Online (Sandbox Code Playgroud)

现在我正在运行它,以测试是否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
Run Code Online (Sandbox Code Playgroud)

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

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


lin*_*ild 9

我刚刚通过手动重新编译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):iconv_impl_name=""在4664行添加(系统配置上的确切行号可能不同):

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

    checking if using GNU libiconv... yes
    
    Run Code Online (Sandbox Code Playgroud)
  6. make

  7. sudo make install

现在我跑了php -i|grep "iconv impl",得到了:

iconv implementation => libiconv
Run Code Online (Sandbox Code Playgroud)

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