【问题标题】:When does fopen fail?fopen 什么时候失败?
【发布时间】:2013-03-09 08:09:34
【问题描述】:

在我的 PHP 代码中,我打开一个文件并向其附加文本。我使用此代码:

$ourFileHandle = fopen($ourFileName, 'a') or die("can't open file");

这发生在 PHP 页面加载时。现在如果两个人同时加载 PHP 页面会发生什么?此代码是否适用于其中一个人,而另一个人是否会执行die()?一般来说,fopen什么时候会失败?

谢谢。

【问题讨论】:

  • 除非您锁定文件,否则这将无法按预期工作,这会损害并发性。几乎可以肯定,无论您在做什么,使用数据库都会做得更好。

标签: php file-io fopen


【解决方案1】:

TL;DR - 只需使用数据库

这不是一个简单的主题。对于多个并发请求,您正在做的事情肯定不会按预期工作,因为大多数系统将允许所有请求打开文件,并且可能多个脚本将能够同时写入文件,您最终可能会如果你这样做,文件中有垃圾。

解决此问题的可能方法很多,但我将在这里介绍我认为最可行的三个。

  1. 使用数据库。这几乎可以肯定是您尝试做的任何事情的最佳解决方案。 RDBMS 将毫不犹豫地处理所有这些并发问题,如果您这样做,您将永远不会遇到任何并发问题。

  2. 使用flock() 请求对文件的独占锁定。此函数使用 advisory 锁定来防止多个并发进程同时访问文件。这将满足您对多个 PHP 进程的需求,但如果其他外部程序不支持 PHP 使用的同一类型的咨询锁定系统,它可能无法与其他外部程序一起使用。
    flock() "blocks" 直到获得锁定文件。这意味着它会损害请求的并发性——一次只有一个请求能够写入文件。此外,它不能保证锁会按照它们被请求的顺序提供服务,因此您可能最终会遇到这样一种情况,即一个请求永远不会获得文件上的锁,而后来到达的其他请求却得到满足。

  3. 使用后台进程来处理文件访问,并让您的脚本与该进程通信。这有点像滚动你自己的 1) 版本,它不适合胆小的人,但如果做得正确,它可以发挥很大的作用。
    使用此模型,可以使用某种形式的进程间通信将需要写入文件的数据中继到后台(持久)进程。然后,此后台进程管理对文件的写入,确保消息以正确的顺序完整写入。通常(当使用 PHP 时)此类 IPC 将使用套接字实现。这很重要,但可能是最强大的解决方案。


从更一般的角度来看,fopen() 通常由于权限问题或低级操作系统问题而失败。操作系统也可以提供“真正的”锁定机制,以防止其他程序打开文件。但是,很难提供真正的“fopen() 可能失败的原因列表”,因为有很多可能性。

显然,如果您尝试以读取模式打开文件并且该文件不存在,则会失败。但是,您上面的代码是以写入模式打开文件 - 如果文件不存在,这不会必然失败 - 如果目录路径存在并且调用进程有权写入该目录,则文件将被创建。

【讨论】:

    【解决方案2】:

    fopen 会失败主要是因为这些原因:

    • 文件不存在
    • 文件权限不允许打开此文件(写入、读取、执行等)
    • 文件被另一个进程(即第 3 方应用程序)使用
    • 文件被另一个 PHP 脚本/资产锁定

    【讨论】:

    • 1) 不相关,a 模式将创建文件 2) 足够公平 3) 和 4) 是同一点并且不相关,因为他没有尝试获取文件的锁定。
    • @DaveRandom 请“加上我的答案”,因为他问:In general, when can fopen fail? :) 这些是 fopen 可能无法正确执行的原因和含义。 :) 干杯
    【解决方案3】:

    fopen 可能会失败,如果您没有权限或存在其他低级操作系统问题,fopening 多次没有问题,但同时写入会导致“条带化”,所以使用(阻止)flock.

    【讨论】:

      猜你喜欢
      • 2017-03-20
      • 1970-01-01
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多