php fwrite() 没有完成将字符串数据写入文件,为啥?

Posted

技术标签:

【中文标题】php fwrite() 没有完成将字符串数据写入文件,为啥?【英文标题】:php fwrite() doesn't finish writing string data to file, why?php fwrite() 没有完成将字符串数据写入文件,为什么? 【发布时间】:2012-03-17 10:12:05 【问题描述】:

我正在尝试将相当大的数据块写入通过 php.ini 中的 fopen() 打开的文件。我使用的协议包装器是 ftp,因此该文件对于运行 php 代码的服务器是远程的。我正在写入的文件位于 Windows 服务器上。

我确认该文件实际上是由我的 php 代码创建的,但问题是文件中的数据不存在 (0KB) 或写入文件过早停止。不知道为什么会这样。

这是我用于处理操作的代码:

$file_handle = fopen($node['ftp'].$path_to_lut, "wb", 0, $node['ftp_context']);
include_once($file);

if ($file_handle)

     fwrite($file_handle, $string);  //$string is inside included $file
     fclose($file_handle);
 else 
     die('There was a problem opening the file.');

当我在本地计算机上托管此代码时,它运行良好,但当我将它上传到我的网络主机(Rackspace Cloud)时,它失败了。这让我相信这是与我在 Rackspace 的服务器配置有关的问题,但想知道我是否可以对我的 php 代码做任何事情以使其更健壮。

有什么办法可以确保 fwrite 真正完成将字符串写入远程机器?

谢谢!

好的,我更改了写入文件的代码,如下所示:

if ($file_handle)

    if ($bytesWritten = fwrite($file_handle, $string) ) 
        echo "There were " . $bytesWritten . " bytes written to the text file.";
    

    if (!fflush($file_handle)) 
        die("There was a problem outputting all the data to the text file.");
    

    if (!fclose($file_handle))  
        die("There was a problem closing the text file."); 
    

 else 

    die("No file to write data to.  Sorry.");


奇怪的是echo语句显示如下:

有 10330 字节写入文本文件。

然而,当我通过 FTP 验证文本文件大小时,它显示为 0K,而文件中的数据实际上已被截断。我无法想象它与 FTP 服务器本身有关,因为如果 PHP 托管在 Rackspace Cloud 上的机器以外的机器上,它就可以工作。

** 更新 ** 我与 Rackspace Cloud 代表交谈过,他提到如果您要从他们的服务器上进行 ftp,他们需要被动 ftp。我设置了远程服务器来处理被动 ftp 连接,并验证了被动 ftp 现在可以通过 OSX Transmit ftp 客户端在远程服务器上运行。我补充说:

ftp_pasv($file_handle, true);

就在 fopen() 语句之后,但我从 PHP 收到一个错误,说我没有为 ftp_pasv() 提供有效资源。如何确保与 PHP 建立的 ftp 站点的连接是 PASV 而不是 ACTIVE 并且仍然使用 fwrite()?顺便说一句,我注意到 Windows 机器报告我的 PHP 代码正在写入的文件在磁盘上是 4096 字节。它永远不会超过这个数量。这导致我将 output_buffering php 值更改为 65536 只是为了进行故障排除,但这也没有解决问题。 . .

** 更新部分 DUEX **

在 Rackspace 云站点产品上解决我的虚拟服务器上的问题被证明太困难了,因为它们没有提供足够的管理员权限。我在 Rackspace 的 Cloud Server 产品上创建了一个非常小的云服务器,并将所有内容配置到我仍然看到 fwrite() 出现相同错误的地步。为了确保我可以将文件从该服务器写入远程服务器,我在云服务器上的 bash shell 中使用了基本的 ftp 命令。它工作得很好。因此,我假设 fwrite() 的 php 实现中存在错误,并且可能是由于某种类型的数据限制问题。当我从本地环境写入远程服务器时,与 Rackspace 云服务器上提供的相比,它的速度较慢,它工作正常。有什么方法可以有效地降低写入速度?随便问问吧:)

** 更新第三部分 *

所以,我接受了@a sad dude 的建议并实现了一个功能,该功能可能会帮助尝试写入新文件并通过 ftp 将其全部发送出去的人:

function writeFileAndFTP($filename=null, $data=null, $node=null, $local_path=null, $remote_path=null)


    //  !Determin the path and the file to upload from the webserver
    $file = $local_path.'/'.$filename;


    //  !Open a new file to write to on the local machine
    if (!($file_handle = fopen($file, "wb", 0)))  
        die("There was a problem opening ".$file." for writing!");
    


    //  !Write the file to local disk
    if ($bytesWritten = fwrite($file_handle, $data) ) 
        //echo "There were " . $bytesWritten . " bytes written to " . $file;
    

    //  !Close the file from writing
    if (!fclose($file_handle)) 
        die("There was a problem closing " . $file);
    

    //  !Create connection to remote FTP server
    $ftp_cxn = ftp_connect($node['addr'], $node['ftp_port']) or die("Couldn't connect to the ftp server.");

    //  !Login to the remote server
    ftp_login($ftp_cxn, $node['user'], getPwd($node['ID'])) or die("Couldn't login to the ftp server.");

    //  !Set PASV or ACTIVE FTP
    ftp_pasv($ftp_cxn, true);


    //  !Upload the file
    if (!ftp_put($ftp_cxn, $remote_path.'/'.$filename, $file, FTP_ASCII)) 
        die("There was an issue ftp'ing the file to ".$node['addr'].$remote_path);  
    

    //  !Close the ftp connection
    ftp_close($ftp_cxn);


【问题讨论】:

include_once($file); - 代码在哪里? 如下所示:$string = "a string about 20 lines long"; var_dump($node['ftp_context']); 输出什么? (删除用户名/密码)。 resource(32) 类型(流上下文) 另外,代码var_dump(stream_get_meta_data($file_handle)); 输出:array(10) ["wrapper_data"]=> NULL ["wrapper_type"]=> string(3) "ftp" ["stream_type"]=> string(14) "tcp_socket/ssl" ["mode"]=> string(2) "r+" ["unread_bytes"]=> int(0) ["seekable"]=> bool(false) ["uri"]=> string(119) "ftp://user:pass@mydomain.com:21/vars.txt" ["timed_out"]=> bool(false) ["blocked"]=> bool(true) ["eof"]=> bool(false) 【参考方案1】:

在某些平台上,fwrite 可以一次性写入的字符串长度受到限制(这就是它返回写入字节数的原因)。您可以尝试循环运行它,但更好的办法是简单地使用file_put_contents,这样可以保证写入整个字符串。

http://www.php.net/manual/en/function.file-put-contents.php

【讨论】:

有趣,谢谢指点。出于好奇,我可以在 .htaccess 文件中设置一个 apache 指令来更改 fwrite() 的数据限制吗? Doubtful ) 另外,如果您使用的是 ftp,我猜它更多的是关于网络。 file_put_contents 有用吗? 不,没有用。文件被创建,但没有数据写入。 通过 Apache,您可以更改 PHP ini 指令(假设 PHP 模块已打开)。虽然不是一个好习惯。但是,您必须检查 PHP 是否有这种选项。 您可能想检查服务器上是否启用了 PHP 模块 - php.net/manual/en/book.ftp.php - 并尝试这样做。或者也许是一些 PHP 库。

以上是关于php fwrite() 没有完成将字符串数据写入文件,为啥?的主要内容,如果未能解决你的问题,请参考以下文章

PHP fwrite() 用于将大字符串写入文件

PHP将数据写入指定文件中

PHP中,fwrite写入文件的时候,怎么换行?

PHP fwrite() 无法写入子目录

linux下php fwrite无法写入文件怎么回事呀

PHP - fwrite() 不写入套接字