4

我有一个从终端运行的 php 脚本,它的作用是:

  • 从数据库中抓取一行数据(表存储要由该脚本专门处理的 JSON 字符串);
  • 将 JSON 字符串转换为数组并准备要插入数据库的数据。
  • 将所需数据插入数据库

这是脚本:

#!/usr/bin/php
<?PHP
    //script used to parse tweets we have gathered from the twitter streaming API
    mb_internal_encoding("UTF-8");
    date_default_timezone_set('UTC');

    require './config/config.php';
    require './libs/db.class.php';

    require './libs/tweetReadWrite.class.php';
    require './libs/tweetHandle.class.php';
    require './libs/tweetPrepare.class.php';
    require './libs/pushOver.class.php';
    require './libs/getLocationDetails.class.php';

    //instatiate our classes
    $twitdb = new db(Config::getConfig("twitterDbConnStr"),Config::getConfig("twitterDbUser"),Config::getConfig("twitterDbPass"));

    $pushOvr = new PushOver();                                          // push error messages to my phone
    $tweetPR = new TweetPrepare();                                      // prepares tweet data
    $geoData = new getLocationDetails($pushOvr);                        // reverse geolocation using google maps API
    $tweetIO = new TweetReadWrite($twitdb,$tweetPR,$pushOvr,$geoData);  // read and write tweet data to the database

    /* grab cached json row from the ORCALE Database
    *
    * the reason the JSON string is brought back in multiple parts is because
    * PDO doesnt handle CLOB's very well and most of the time the JSON string
    * is larger than 4000 chars - its a hack but it works
    *
    * the following sql specifies a test row to work with which has characters like €$£ etc..
    */
    $sql = "
            SELECT a.tjc_id
                 , dbms_lob.substr(tweet_json, 4000,1) part1
                 , dbms_lob.substr(tweet_json, 8000,4001) part2
                 , dbms_lob.substr(tweet_json, 12000,8001) part3
            FROM twtr_json_cache a
            WHERE a.tjc_id = 8368
            ";

    $sth = $twitdb->prepare($sql);
    $sth->execute();
    $data = $sth->fetchAll();

    //join JSON string back together
    $jsonRaw = $data[0]['PART1'].$data[0]['PART2'].$data[0]['PART3'];

    //shouldnt needs to do this, doesnt affect the outcome anyway
    $jsonRaw = mb_convert_encoding($jsonRaw, "UTF-8"); 

    //convert JSON object to an array
    $data = json_decode($jsonRaw,true);

    //prepares the data (grabs the data I need from the JSON object and does some
    //validation etc then finally submits to the database
    $result = $tweetIO->saveTweet($data); // returns BOOL
    echo $result;
?>

现在,如果我从终端运行它./proc_json_cache.php或者php proc_json_chache.php它工作正常,数据到达数据库 UTF-8 编码并且一切都很好,数据库中的数据看起来像这样£$@€ < test

如果我通过 CRON 调用这个脚本,它仍然会保存数据,但像 €£ 等特殊字符只是正方形,数据库中的数据看起来像这样��$@��� < test

到目前为止,我尝试将以下几行添加到我的 crontab 中:

TERM=xterm
SHELL=/bin/bash

这样它就匹配了我当前的 shell ENV 会话设置,并将以下内容添加到调用我的 php 脚本的 bash 脚本中:

export NLS_LANG="ENGLISH_UNITED KINGDOM.AL32UTF8"
export LANG="en_GB.UTF-8"

再次匹配我当前的 shell ENV 设置,但是当脚本从终端中的 cron vs direct 运行时,我仍然遇到字符编码问题。

有没有其他人遇到过类似的问题,可以说明如何解决这个问题?提前致谢。

编辑:

以下是有关服务器的更多信息:

操作系统:SUSE Linux Enterprise Server 11 PHP:5.2.14

4

2 回答 2

2

尝试添加到调用您的 php 脚本的 bash 脚本中:

unset LANG LANGUAGE LC_CTYPE
export LANG=en_GB.UTF-8 LANGUAGE=en LC_CTYPE=en_GB.UTF-8

请参阅:回复:Crontab 的字符集不在 utf-8 中

于 2013-03-18T14:35:17.840 回答
0

好的,所以在调查了这个问题几个小时之后,它似乎与未传递给 PHP 脚本的 shell 会话变量有关。

我忘记提到的一件事是脚本不是由 cron 作业直接调用,而是由另一个守护进程类型的 PHP 脚本调用,该脚本检查脚本是否已经运行,如果没有,它将用于pcntl_exec()调用脚本。

现在因为我没有将环境设置作为第三个参数传递,这意味着我在 crontab 中设置的任何 shell 环境设置都不会传递给我的脚本(共享当前进程空间)。

所以我实际上在做的是:

pcntl_exec($script, $args); //script take over the process space
                            //but no continued shell env settings

当我应该做的是:

$a = get_defined_vars();
pcntl_exec($script, $args, $a['_SERVER']); //script take over the process space
                                           //but with shell env settings continued

有关更多信息,请参阅pcntl_exec()的 php.net 手册。

于 2013-03-20T19:40:26.607 回答