【问题标题】:Print_r() to PHP error_log() not working. (non-printing characters)Print_r() 到 PHP error_log() 不起作用。 (非打印字符)
【发布时间】:2013-03-28 07:56:34
【问题描述】:

我在辅助类 Utility::error_log() 中有一个静态方法,用于帮助我们优雅地调试 PHP 中的 HUGE 对象。该方法及其辅助方法 Utility::toArray() 如下:

static function error_log($message, $data=null, $max=2)
{

    if(is_array($data) || is_object($data))
        $data = print_r(self::toArray($data, $max),true);
    if(is_array($message) || is_object($message))
        $message = print_r(self::toArray($message, $max),true);

    if(!empty($data))
        $data = "\n".$data;

    if (!strstr($message, PHP_EOL))
        $message = str_pad(" ".$message." ", 50,'=',STR_PAD_BOTH);

    error_log($message.$data);

}

static function toArray($object, $max = 2, $current = 0)
{
    if($current > $max)
        return ucfirst(gettype($object)).'( ... )';

    $current++;
    $return = array();
    foreach((array) $object as $key => $data)
        if (is_object($data))
            $return[$key] = self::toArray($data, $max, $current);
        elseif (is_array($data))
            $return[$key] = self::toArray($data, $max, $current);
        else
            $return[$key] = $data;

    return $return;
}

现在这可能有点看不出来,但要点是,toArray 将一个巨大的对象(大量递归)缩小了一个数量级,并将所有属性作为数组或字符串返回。使用起来更容易...想法是 print_r($array,true) 然后将数组变成一个字符串,然后我们记录它。

但是,这并没有按预期工作。结果是:

[05-Apr-2013 05:29:00] ==================================== PERSISTING SUITS & SHIRTS ===================================
Array
(
    [

然后什么也没有,当我调用 print_r($data) 并打印到浏览器时,我得到:

Array
(
    [BRS\PageBundle\Entity\Pageroot_folder_name] => Pages
    [id] => 43
    [title] => Suits & Shirts
    [depth_title] => Suits & Shirts
    [description] => ( ... AND SO ON ... )

在你说这是一个error_log()长度限制之前,我先提一下我可以成功$data = var_export($data,true)并将结果发送到error_log()没有问题:

[05-Apr-2013 06:00:08] ==================================== PERSISTING SUITS & SHIRTS ===================================
array (
    '' . "\0" . 'BRS\\PageBundle\\Entity\\Page' . "\0" . 'root_folder_name' => 'Pages',
    'id' => 43,
    'title' => 'Suits & Shirts',
    'depth_title' => 'Suits & Shirts',
    'description' => ( ... AND SO ON ... )

有什么问题?为什么它适用于var_export($data,true)print_r($data,false),但不适用于print_r($data,true)??

【问题讨论】:

    标签: php arrays object error-log non-printing-characters


    【解决方案1】:

    答案是不可打印的字符。在对象到数组的转换以及它们的各种属性到字符串的转换中,这些字符串包含我们从未见过的非打印控制字符,但它们的存在打破了 PHP 的error_log()

    解决方案相当简单,但必不可少:

    $data= preg_replace('/[^\x0A\x20-\x7E\xC0-\xD6\xD8-\xF6\xF8-\xFF]/','',$data);
    
    // Or to preserve extended characters, use the below expression.
    // Mind you many of these still may not display correctly in logs.
    $data= preg_replace('/(?!\n)[[:cntrl:]]+/','',$data);
    

    在将 $message 发送到错误日志之前调用,这会删除许多非打印字符,同时保留许多我发现已删除的其他 pregs 字符。以防万一您需要它们:

    \x0A = [newline]
    \x20-\x7E = [space] ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
    \xC0-\xD6 = À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö
    \xD8-\xF6 = Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö
    \xF8-\xFF = ø ù ú û ü ý þ ÿ
    

    最后,进行了一些额外的重写,以隔离一些功能以供其他地方使用,但最终的解决方案同样简单。

    编辑: 经过进一步审查,这似乎与Bug #64439 - "\0 causes error_log strings to be truncated" 更具体相关。

    对于那些想知道的人,\0(或 \x00 或 \x0)是 NULL 字符,在上述特定情况下,它是将对象转换为数组的结果,它返回的 Key 值为 @987654325 @。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-13
      • 2021-02-12
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 2012-09-04
      • 1970-01-01
      相关资源
      最近更新 更多