2013-03-18 53 views
4

我有我从这里的终端上运行PHP脚本它做什么:为什么从CRON运行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.phpphp proc_json_chache.php终端正常工作数据库UTF数据到达-8编码,一切正常,数据库中的数据看起来像这样£[email protected]€ < test

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

那么遥远的事情,我已经试过要添加以下行到我的crontab:

TERM=xterm 
SHELL=/bin/bash 

这是因此它符合我目前的外壳ENV会话设置,并且还加入了以下以调用我的PHP的bash脚本脚本:

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

又符合我目前的shell的环境设置,但是当脚本是从cron运行VS直接在终端我仍然得到字符编码问题。

有没有其他人有类似的问题,可以阐明如何解决这个问题? 在此先感谢。

编辑:

这里是有关服务器的一些信息:

OS:SUSE Linux Enterprise Server 11 PHP:5.2.14

+0

尝试在控制台上键入'env'并检查脚本中是否应该导出其他'env'值。 – fedorqui 2013-03-18 10:50:08

+0

我应该寻找哪些其他值? – 2013-03-18 10:55:34

+0

而不是UTF-8,你可以尝试ISO-8859-1,并告诉它是否有效。 – Fr0zenFyr 2013-03-18 11:00:18

回答

0

好的,经过好几个小时的调查后发现,它似乎与shell会话变量没有传递给PHP脚本有关。

有一件事我忘了提的是,该脚本没有被直接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手册,了解更多信息。

2

尝试增加以调用PHP脚本的bash脚本:

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

参见:Re: Crontab's charset not in utf-8

+0

我没有看到之前的链接,这就是为什么我在bash脚本中导出LANG,但我尝试了你的建议,它没有工作:( – 2013-03-18 14:52:09

+0

'unset'是多余的。 – 2013-03-18 15:40:36

相关问题