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() 没有完成将字符串数据写入文件,为啥?的主要内容,如果未能解决你的问题,请参考以下文章