为什么PHP的fwrite()函数无法完成将字符串数据写入文件?

7
我正在尝试使用php中的fopen()向一个通过ftp打开的文件写入大块数据。该协议包装器是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.');
}

当我将这段代码托管在本地机器上时,它可以正常工作,但是当我将其上传到我的Web主机(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连接,并验证了通过OSX Transmit FTP客户端现在可以在远程服务器上使用被动FTP。我添加了:
ftp_pasv($file_handle, true);

在fopen()语句之后,但我收到PHP的错误提示说我没有提供有效的资源给ftp_pasv()。我该如何确保PHP连接到ftp站点是PASV而不是ACTIVE,并仍然使用fwrite()?顺便说一下,我注意到Windows机器报告我的PHP代码正在写入的文件在磁盘上为4096字节。它从未超过这个数量。这导致我将output_buffering php值更改为65536只是为了进行故障排除,但这也没有解决问题...
** PART DUEX更新 **
在Rackspace Cloud Sites产品上调试问题太困难了,因为他们没有足够的管理员权限。我在Rackspace的Cloud Server产品上创建了一个非常小的云服务器,并将所有内容配置到我仍然看到与fwrite()相同的错误。为了确保我可以从该服务器写入文件到远程服务器,我在云服务器上的bash shell中使用基本的ftp命令。它很好用。因此,我认为php实现fwrite()中存在某种类型的数据限制问题的bug。当我从具有缓慢上行速度的本地环境向远程服务器写入时,它可以正常工作。有没有办法有效地降低写入的速度?只是问一下:)
** PART III更新 **
因此,我采纳了@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); - 这段代码在哪里? - hakre
资源(32)的类型为(stream-context)。 - ariestav
此外,代码 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) } - ariestav
你能确保你要写入的文件夹和文件有有效的权限吗?试着用 chown 改为 777,然后再次尝试。如果可以工作,那么你至少会知道权限存在问题。底线是 FTP 用户必须具有写入所写入的文件夹的访问权限。 - Jaspreet Chahal
我非常确定ftp用户对该文件夹具有写入权限。正如我在帖子中所写的那样,文件已经被创建并写入了,但在某些情况下,数据会被截断或文件为空。我非常怀疑这不是权限问题。 - ariestav
显示剩余5条评论
1个回答

5
在一些平台上,fwrite 函数在一次操作中可以写入的字符串长度是有限制的(这就是为什么它会返回已经写入的字节数)。你可以尝试使用循环来执行多次写入操作,但更好的方法是直接使用 file_put_contents 函数,它保证整个字符串都将被写入。
参考链接:http://www.php.net/manual/en/function.file-put-contents.php

有趣,感谢指引。出于好奇,我能否在.htaccess文件中设置一个Apache指令来更改fwrite()的数据限制? - ariestav
不确定),而且如果你正在使用ftp,更多的是关于网络方面的问题,我猜测。file_put_contents函数运作了吗? - a sad dude
不行,没有起作用。文件已经被创建了,但是没有数据被写入其中。 - ariestav
通过Apache,您可以更改PHP ini指令(假设已启用PHP模块)。虽然这不是一个好的实践方法。但是,您必须检查PHP是否具有此类选项。 - Christian
你可能需要检查服务器上是否启用了PHP模块 - http://www.php.net/manual/en/book.ftp.php - 并尝试使用它。或者也许可以使用一些PHP库。 - a sad dude
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接