【问题标题】:file_put_contents() messing with updated array valuesfile_put_contents() 弄乱了更新的数组值
【发布时间】:2013-12-20 18:36:42
【问题描述】:

抱歉,如果标题有点混乱。

我下面的结果指出了正在发生的事情。


这个问题已经变得相当广泛,所以我在这里强调这两件事:

请在底部查看我的更新,了解合理的原因。

整个文件:(见第 86 行)http://codepad.org/oIXaZZaB


这是怎么回事:

我有这个数组,其中包含每个语言代码的计数整数。

$downloads = [
    'all' => [
        'nl-BE' => 0,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ],
    'unique' => [
        'nl-BE' => 0,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ]
];

$_GET['langCode']参数中检索到的键,总是计数$downloads['all']中的对应键。

我还检查访问者是否是唯一的并且之前已经使用过相同的$langCode。如果他之前没有使用过相同的$langCode,则计数也会添加到$downloads['unique']中的对应键中。

这是通过以下代码完成的:

$uniqueVisitors = [
    '127.0.0.1' => [ 'en-UK' ]
];


if ($uniqueVisitors == null)
{
    $uniqueVisitors = [
        $ipNew => []
    ];
}



$countUnique = 1;


/*  Check Unique Visitors  */

if (isset($uniqueVisitors[$ipNew]))
{
    if (in_array($langCode, $uniqueVisitors[$ipNew]))
    {
        $countUnique = 0;
    }

    else $uniqueVisitors[$ipNew][] = $langCode;
}

else $uniqueVisitors[$ipNew] = [ $langCode ];



/*  Update Data  */

$downloads['all'][$langCode]++;

if ($countUnique)
{
    $downloads['unique'][$langCode]++;
}


/*  Save Data  */

file_put_contents('data/unique-visitors.json', json_encode($uniqueVisitors));
file_put_contents('data/downloads.json', json_encode($downloads));

现在奇怪的是,当我运行脚本时,有时会计算多个键,即使 $langCode 只包含一个键(例如 'nl-NL'

当使用'en-UK' 时,'en' 通常也会被计算在内。 'fr-FR''fr-BE' 也是如此。 还有'nl-NL''nl-BE'

这主要发生在使用的 langCode 计数仍为 0 时 但它似乎也以随机顺序发生。

现在你可能认为这是由于 langCodes 使用 as keys,但我使用了 零索引键也,同样的结果!

例如:

/*  Retrieved first from JSON file  */

$downloads = [
    'all' => [
        'nl-BE' => 0,
        'nl-NL' => 2,
        'fr-BE' => 1,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ],
    'unique' => [
        'nl-BE' => 0,
        'nl-NL' => 1,
        'fr-BE' => 1,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ]
];

$uniqueVisitors = [
    '127.0.0.1' => [ 'nl-NL', 'fr-BE' ]
];


/*  Result after running script with 'en-UK' langCode  */

$downloads = [
    'all' => [
        'nl-BE' => 0,
        'nl-NL' => 2,
        'fr-BE' => 1,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 1,
        'en'    => 1   // Why is this one counted ?
    ],
    'unique' => [
        'nl-BE' => 0,
        'nl-NL' => 1,
        'fr-BE' => 1,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 1,
        'en'    => 1   // Why is this one counted ?
    ]
];

$uniqueVisitors = [
    '127.0.0.1' => [ 'nl-NL', 'fr-BE', 'en', 'en-UK' ]  //  'en' stored as well ?
];

整个文件:(见第 86 行)http://codepad.org/oIXaZZaB


更新:

当我不使用两个 file_put_contents() 函数将更新后的数据保存回他们的文件时,只是进行一些测试和转储,整个计数确实按预期工作!

所以看起来这两个file_put_contents() 函数,用于保存(正确)更新的数据,以某种方式干扰,并在执行时更改了一些计数。

但是怎么做?!

有人对这种意外行为有更好的理解吗?


更新 2:

当我在 file_put_contents() 函数中省略 json_encode() 时,我收到“数组到字符串转换”错误,两次用于保存我的计数数据 ($downloads):

Notice: Array to string conversion in /Applications/MAMP/htdocs/project/downloads/downloads.php on line 89

Notice: Array to string conversion in /Applications/MAMP/htdocs/project/downloads/downloads.php on line 90

Notice: Array to string conversion in /Applications/MAMP/htdocs/project/downloads/downloads.php on line 90

file_put_contents('data/unique-visitors.json', json_encode($uniqueVisitors));
file_put_contents('data/downloads.json', json_encode($downloads));  // This one is called twice!

那为什么要执行两次呢?那里甚至没有一个循环。


更新 3:

我的 JSON 编码 $downloads 数据正确显示了更新后的值。

但是一旦我使用file_put_contents() 存储更新的$downloads 数据,它就会与更新的值混淆。即使我在使用file_put_contents 之前/之后转储更新的数据,它也显示混乱。

初始$downloads数组:

$downloads = [
    'all' => [
        'nl-BE' => 0,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ],
    'unique' => [
        'nl-BE' => 0,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ]
];

$_GET['langCode'] = 'nl-BE'更新值:

$downloads = [
    'all' => [
        'nl-BE' => 1,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ],
    'unique' => [
        'nl-BE' => 1,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ]
];

当我尝试使用file_put_contents() 存储更新后的数组时:

$downloads = [
    'all' => [
        'nl-BE' => 2,  // Why this increment?
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ],
    'unique' => [
        'nl-BE' => 1,
        'nl-NL' => 0,
        'fr-BE' => 0,
        'fr-FR' => 0,
        'de-DE' => 0,
        'it-IT' => 0,
        'en-UK' => 0,
        'en'    => 0
    ]
];

奇怪的是,当我使用file_put_contents 时,更新后的$downloads 显示错误更新,当转储在同一个脚本运行时(file_put_contents 之前和之后)。我什至不必使用file_get_contents 来检索错误保存的数据。


更新 4:(原因)

看来是 Safari 7 导致了这个错误。

Firefox 和 Chrome 都在完美地运行这个脚本。

我可以在哪里举报?


htaccess:

如果没有 htaccess 文件,同样的错误仍然会发生。

<IfModule mod_rewrite.c>

    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-l

    RewriteRule ^(.+)/?$ index.php?lang=$1 [QSA,NC,L]


</IfModule>

【问题讨论】:

  • 无法用您的代码重现该问题。
  • @CBroe 这是整个文件:http://codepad.org/67sp3INu
  • 更新了整个文件,见第 86 行:http://codepad.org/Y9aZurkX
  • 您的 Update 1Update 2 中标记的 file_put_contents() 不会执行两次。您收到两次错误消息,因为$downloads 包含 2 个子数组,并且它们都未能转换为字符串。如果该数组包含 3 个子数组,您将收到 3 次错误消息,您可以尝试一下。
  • 至于你原来的问题,我也无法重现你的bug,我也没有看到你的示例程序有任何根本性的缺陷。错误的来源必须在其他地方。

标签: php arrays


【解决方案1】:

我也无法重现您的错误。在我看来,您的脚本被调用了两次(请参阅“所有”中的项目增加但不是“唯一”。

file_put_contents() 没有问题。您可以通过在脚本中添加类似这样的内容来验证这一点:

<?php

mail('you@domain.tld', 'script executed at '.time(), '');

// your code ...

我建议复制您的脚本,删除所有 html 代码并在带有虚拟数据的终端中执行它

php yourscript.php

这是我的代码:http://codepad.org/XhS6uEz1

你会看到它的行为是正确的。

此外,您可以禁用一些php module that could be responsible for such bugs,但我认为这不是问题。

【讨论】:

  • 我的脚本怎么可能被调用两次?这没有意义。我什至在更新部分的末尾使用exit;
  • 一旦我使用file_put_contents,我更新的数组就会保存错误的更新值。不使用file_put_contents,它会转储正确更新的值。
  • 你的整个脚本被调用了两次(也被调用了)。就像在浏览器中按 f5 一样。请在您的终端中运行它。
  • 确实在终端中运行良好。但我完全不知道我的脚本如何在 localhost 上多次运行。 (以及在网络上的另一台服务器上)
  • 并且要明确一点:'unique' 仅在未为 IP 地址设置 langCode 时才需要增加。所以对我来说它只会保持 1。
【解决方案2】:

查看您的服务器访问日志,看看您是否可以确定第二次调用脚本的来源。我已经安装了类似的插件,检查页面加载速度的调试器或插件可以再次调用该页面。

【讨论】:

  • 我尝试启用 MAMP 的访问日志,如 this thread 中所述,但日志文件不会出现。但是,我已经删除了 Safari 7 中的所有扩展程序和插件,结果相同。
猜你喜欢
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多