与Apache/PHP/FreeTDS不一致会导致特殊字符,但与命令行中的PHP/FreeTDS不同


Inconsistent results in special characters with Apache/PHP/FreeTDS, but not with PHP/FreeTDS from command line

我有两台相同的服务器(称为测试和生产),分别是Linux Red Hat Enterprise Linux Server 6.2版(Santiago)、PHP 5.4.2版、Apache 2.4.2、OpenSSL/0.9.8s、freeTDS 0.92-dev(不是最好的,但我暂时无法更改),以及一台单独的Windows服务器和Microsoft SQL Server。

我有一个名为testfs1.PHP的PHP脚本,它从数据库中读取一个字符串,始终相同,并打印长度:没有其他内容。当然,最初的情况要复杂得多,但我尽了一切努力来简化。

数据库字段为NVARCHAR,所有组件都设置为使用UTF-8。

正常情况下一切正常:脚本显示预期的字符串长度。但是,每隔几个小时甚至几天,只在生产服务器上(它承载了几个大量使用的应用程序),这个错误就会"激活":web服务器开始错误地显示从数据库中提取的特殊字符。有时,bug会在几分钟后自行"停用";上次,它持续了几个小时,然后我运行

service httpd restart

并且该错误被停用。

在bug激活的时间范围内,它是一致的:所有对web服务器的页面testfs1.php的请求都显示错误的结果;但是,当我手动运行时

php testfs1.php

在服务器的命令行上,错误永远不会出现,即使它处于活动状态。

这是我日夜运行的Bash脚本,用于监控bug的激活:

#!/bin/bash
while : ; do
    echo -n `date +%H%M%S`
    wget https://www.mydomain.org/testfs1.php -o /dev/null
    echo -n "("
    cat testfs1.php
    echo -n ") "
    rm testfs1.php
    sleep 2
done

我用来重现这个问题的PHP脚本:

<?php
$Conn = mssql_connect( 'PROD', 'user', 'password' ) ;
mssql_select_db( "DBPROD", $Conn ) ;
$Ret = mssql_query( "SELECT lname FROM people WHERE people_key=123", $Conn ) ;
list( $s ) = mssql_fetch_row( $Ret ) ;
print strlen( $s ) ;
?>

以下是freeTDS使用的locales.conf:

[default]
    date format = %b %e %Y %I:%M:%S:%z%p
    language = us_english
    charset = UTF-8
[en_US]
    date format = %b %e %Y %I:%M:%S:%z%p
    language = us_english
    charset = UTF-8
[es_ES]
    date format = %b %e %Y %I:%M:%S:%z%p
    language = us_english
    charset = UTF-8
[pt_BR]
    date format = %b %e %Y %I:%M:%S:%z%p
    language = us_english
    charset = UTF-8
[it_IT]
    date format = %b %e %Y %I:%M:%S:%z%p
    language = us_english
    charset = UTF-8

这个问题最令人困惑的特殊性摘要:

  1. 当脚本从命令行使用PHP运行时,错误永远不会发生,只从Apache运行
  2. Bug在不同的时刻"激活",每几个小时或几天一次,并自行或通过"服务httpd重启"停用"
  3. 当在freeTDS使用的locales.conf中,行[default]/charset缺失时,bug会更频繁地自发激活和停用(每隔几秒钟)
  4. 当同一服务器上的另一个应用程序使用gettext时,错误会自发地激活和停用(每隔几秒钟)

一位同事暗示这可能是内存问题,考虑到重新启动Apache可能会释放内存,这是有道理的,并解释了为什么在流量最小的测试服务器上没有发生这种情况。我不相信。

你能想象这种情况的可能原因和解决方案吗?

坦率地说,我不知道是什么导致了这种不一致的工作。但我想建议你改变FreeTDS&unixODBC到稳定版本。由于FreeTDS缺乏文档&支持我一直在使用v0.82。而且效果很好。

https://gitorious.org/freetds/mars-freetds/source/52e59affc0110c5ddd379ef1e45c4554123f27b5:README#L2

另一种查找问题详细信息的方法是在testfs1.php中使用PDO MsSQL。通过这种方式,如果本地MsSQL扩展对这种不一致性有任何影响,您可以更好地解决问题。