Linux 如何强制 PHP 使用 iconv 的 libiconv 版本而不是 CentOS 安装的 glibc 版本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4743080/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I force PHP to use the libiconv version of iconv instead of the CentOS-installed glibc version?
提问by Randell
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.
我正在处理的代码在 Windows XP 和 Mac OS X 上完美运行。在 CentOS(以及 Fedora 和 Ubuntu)上测试它时,它无法正常工作。搜索网络使我得出结论,这是导致问题的glibc
版本iconv
。所以现在我需要Zend Lucene的libiconv
版本iconv
才能正常工作。
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.
我已经下载了 libiconv 并使用--prefix=/usr/local
,对其进行了配置make
,然后make install
没有任何错误。似乎它已成功安装,因为执行时/usr/local/bin/iconv --version
说版本是libiconv
. 虽然简单iconv --version
还是给出了glibc
版本。
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
.
然后我使用--with-iconv=/usr/local
. 但是,仍然phpinfo()
显示iconv
正在使用的是glibc
版本。我也已经尝试过使用--with-iconv-dir
或使用其他几种编译/usr/local/bin/php
。
Of course, I restarted the web server after recompiling PHP.
当然,我是在重新编译PHP后重启了web服务器。
I have the following line in my /etc/httpd/conf/httpd.conf
:
我在我的以下行/etc/httpd/conf/httpd.conf
:
LoadModule /usr/lib/httpd/modules/libphp5.so
and libphp5.so
is actually in /usr/lib/httpd/modules
.
并且libphp5.so
实际上在/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.
phpinfo()
显示 PHP 5.3.3。我也 yum 删除了预安装的 PHP 5.1.* 只是为了确保。但是 iconv 仍然使用 glibc 版本。
ldd /usr/lib/httpd/modules/libphp5.so
gives
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)
This is a cross-post from: NullPointer.ph
这是来自:NullPointer.ph的交叉帖子
采纳答案by linuxbuild
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:
我刚刚通过手动重新编译 php iconv 扩展将我的 php-5.3.3 从 glibc 的 iconv 更改为 GNU libiconv。按着这些次序:
- download php-5.3.3 source codepackage
- 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
- 下载php-5.3.3源码包
- 解压并进入
php-5.3.3/ext/iconv
子目录 - 执行
phpize
命令(如果你没有这样的命令,那么安装php-devel
包) (*) 编辑配置文件 (
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< ...
./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:
现在我运行php -i|grep "iconv impl"
并得到:
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.
* 这个技巧强制配置选择 GNU libiconv 而不是 glibc 的 iconv。默认情况下,它在第一步检查 glibc 的 iconv 并且根本不检查 GNU libiconv。
回答by Pablo Alba
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.
我不了解 CentOS,但在基于 debian 的发行版中,例如 Ubuntu,您可以选择要启动的程序版本,在 /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.
因此,如果您更改符号链接 /etc/alternatives/iconv 以指向 /usr/local/bin/iconv,则此点应使用正确的版本。
回答by Pablo Alba
Are you sure that LD_LIBRARY_PATH
is set properly for httpd (web server) process?
If not, try setting it like:
您确定LD_LIBRARY_PATH
为 httpd(Web 服务器)进程正确设置了吗?如果没有,请尝试将其设置为:
export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH}"
... in the script that starts the process (i.e. apachectl
).
... 在启动进程的脚本中(即apachectl
)。
The ldd
output you showed looks correct, but you invoked ldd
from user's environment, and httpd's might be different.
ldd
您显示的输出看起来是正确的,但您是ldd
从用户的环境中调用的,而 httpd 的可能不同。
It could also help to set PATH to "/usr/local/bin:${PATH}", just in case.
将 PATH 设置为“/usr/local/bin:${PATH}”也有帮助,以防万一。
回答by peoro
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
).
您的模块 ( libphp5.so
) 链接到提供相同符号的两个共享库(在这种情况下,符号是iconv
,库是libiconv.so.2
并且可能是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.
发生这种情况时,将使用第一个加载的符号:可能libc.so.6
之前已加载libiconv.so.2
,因此它是为您提供iconv
符号的那个。
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.
你可以强制动态加载器先加载一个库;您可以通过将LD_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:
我不是 Apache 的专家,所以我不完全确定它是如何工作的,它如何启动它的进程以及它使用的进程,但我认为LD_PRELOAD
在运行 apache 之前进行设置应该可以解决问题:
LD_PRELOAD=/usr/local/lib/libiconv.so.2
A little example to show LD_PRELOAD
in action:
一个显示LD_PRELOAD
在行动中的小例子:
Will compile myfopen.c
as a shared library (myfopen.so
): it will provide a fopen
symbol (already defined in libc
):
将编译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
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 .
):
编译printfopen.c
为可执行文件 ( printfopen
),它只打印fopen
; 将它链接到libc
和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)
Now I'm running it, to test if LD_PRELOAD
works:
现在我正在运行它,以测试是否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
By default it loads libmyfopen
before libc
, then I tried to force loading libc
and then libmyfopen
first.
默认情况下它加载libmyfopen
before libc
,然后我尝试强制加载libc
,然后libmyfopen
首先加载。
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.
我猜在您的情况下libc
之前已加载,libiconv
因为前者是由应用程序(apache?)在加载 PHP 模块之前加载的。
回答by Nopius
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):
我知道,这个问题已经得到解答并且几乎死了,但最近我试图找到一种使用 libiconv 编译 PHP 的方法,因为在 PHP 中我无法转换“?” 从 UTF8 到 CP1251,即使使用 iconv //忽略。但我找到了另一种无需重新编译即可为我工作的解决方案(只需使用 //TRANSLIT):
iconv("UTF8", "CP1251//TRANSLIT//IGNORE", $text)
iconv("UTF8", "CP1251//TRANSLIT//IGNORE", $text)
//TRANSLIT will transliterate ONLYunknown characters (not all, as some may guess), so it converts Russian 'ё', but transliterates unknown '?' to 0x95 (which looks the same in the target charset).
//TRANSLIT 将仅音译未知字符(并非所有字符,有些人可能会猜到),因此它会转换俄语 'ё',但会音译未知字符 '?' 到 0x95(在目标字符集中看起来相同)。