php - Angular POST 到 PHP : file_put_contents not writing/wrong submit order

标签 php angular http post file-put-contents

我正在使用 angular http 将数据从我的 Ionic 应用程序发布到 PHP 脚本。在该脚本中,一个 json 文件被读取和解码,以便可以附加传入的数据,然后将其写回到文件中。

这基本上可以正常工作,但在某些情况下 file_put_contents 不会写入新的编码数组和/或提交顺序被弄乱了。

typescript :

this.names.forEach(name => {
    this.http.post("http://myServer.test/saveNames.php", {name: name["name"], mode: name["mode"]}).subscribe(
        err => {
            errors.push(name["name"]);
        }
    );
});

Typescript 发布数据:

(3) [{…}, {…}, {…}]
0: {name: "User 1", mode: "namesM"}
1: {name: "User 2", mode: "namesW"}
2: {name: "User 3", mode: "namesJobs"}
length: 3

PHP 脚本:

$postData = file_get_contents("php://input");
    if (isset($postData)) {
    $request = json_decode($postData, true);

    var_dump("Data after decode:");
    var_dump($request);

    $inp = file_get_contents('names.json');

    if (($inp) == "") return; // Return so file does not get messed up

    $allNames = json_decode($inp, true);

    var_dump("File, no decode:");
    var_dump($inp);
    var_dump("File, decoded:");
    var_dump($allNames);

    $allNames[] = $request;

    var_dump("File content + new data:");
    var_dump($allNames);
    var_dump("All data pretty printed:");
    var_dump(json_encode($allNames, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));

    file_put_contents('names.json', json_encode($allNames, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); // mit UTF8s
}

names.json 在任何写入之前(初始状态):

[]

发布完成后的 names.json:

[
    {
        "name": "User 1",
        "mode": "namesM"
    },
    null
]

该文件具有 777 权限,并且在此过程中未打开。如您所见,只写了一个名字,插入了一个空值,然后什么也没有发生。

当我检查 Chrome 网络选项卡时,我注意到在用户 1(其 pretty-print json 看起来不错)之后,订单被弄乱了。在 User 1 之后,接下来是 User 3,但是 file_get_contents(names.json) 返回的是空数组,因此实际上并没有写入 User 1。用户 3 也产生了正确的 json,但之后用户 2 紧随其后,file_get_contents('names.json') 为空(如空字符串),因此它在此处停止。

但是我不明白为什么文件中仍然有用户 1,为什么其他两个没有写成一般。

这是 Chrome 网络选项卡中的 var_dumps():

用户 1(第一个):

string(18) "Data after decode:"
array(2) {
  ["name"]=>
  string(6) "User 1"
  ["mode"]=>
  string(6) "namesM"
}
string(16) "File, no decode:"
string(2) "[]"
string(14) "File, decoded:"
array(0) {
}
string(24) "File content + new data:"
array(1) {
  [0]=>
  array(2) {
    ["name"]=>
    string(6) "User 1"
    ["mode"]=>
    string(6) "namesM"
  }
}
string(24) "All data pretty printed:"
string(66) "[
    {
        "name": "User 1",
        "mode": "namesM"
    }
]"

用户 3(第二个!?):

string(18) "Data after decode:"
array(2) {
  ["name"]=>
  string(6) "User 3"
  ["mode"]=>
  string(9) "namesJobs"
}
string(16) "File, no decode:"
string(2) "[]"
string(14) "File, decoded:"
array(0) {
}
string(24) "File content + new data:"
array(1) {
  [0]=>
  array(2) {
    ["name"]=>
    string(6) "User 3"
    ["mode"]=>
    string(9) "namesJobs"
  }
}
string(24) "All data pretty printed:"
string(69) "[
    {
        "name": "User 3",
        "mode": "namesJobs"
    }
]"

用户 2(第三个!?)

string(18) "Data after decode:"
array(2) {
  ["name"]=>
  string(6) "User 2"
  ["mode"]=>
  string(6) "namesW"
}

对于冗长的文字,我真的很抱歉,但我尝试了几个小时后还是找不到解决方案。我希望我记录得足够好,感谢您的帮助!

最佳答案

在我看来,这些问题中的任何一个都可能发生:

  1. 您运行 PHP 的网络服务器可能正在并行(多线程)运行每个 POST 请求,这会导致文件部分打开或忙于由一个请求写入,而另一个请求正忙于尝试写入阅读它。

  2. 您的网络服务器的文件系统告诉 PHP 文件已写入且一切正常,而实际上,在实际将数据实际写入磁盘之前,它仍在忙于在内部缓存数据。因此,当下一个读取文件的请求到来时,它还没有完全写入。

因此您可能尝试的解决方案是:

  1. 尝试使用带有 LOCK_EX 标志的 file_put_contents 和 file_get_contents 来专门读取和写入文件。参见 http://php.net/manual/en/function.file-put-contents.php

  2. 为什么要从同一个客户端发送多个 POST 请求?你应该做这样的事情:

var allNames = [];
this.names.forEach(name => {
    allNames.push({name: name["name"], mode: name["mode"]});
    });


this.http.post("http://myServer.test/saveNames.php", allNames, ....);

所以一次发送整个名称数组,就可以避免遇到这个问题。

磁盘操作非常慢,因此您不应该指望它们跟上来自客户的请求。您应该只进行尽可能少的磁盘操作,并尽可能多地对数据进行批处理。

关于php - Angular POST 到 PHP : file_put_contents not writing/wrong submit order,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54484278/

相关文章:

PHPstorm PHPunit 代码共同覆盖

authentication - Angular 重定向到登录页面

http - Golang文件上传: close connection if file is too large

python - 如何使用 python 成功下载字节范围而不是完整文件?

php - 如何使用仅返回具有特定字段值的行的 MATCH AGAINST 方法搜索 MySQL 数据库?

php - 拉维尔 4 : How to Change Laravel getQueryLog to complete SQL command

php - 将一张表与其自身左连接

javascript - 在小屏幕上隐藏/显示图像

Angular5 : where are "converters" ?(即像 JSF)

http - Flutter - VideoPlayer - 在从网络数据源构建视频 Controller 时支持 http header