fopen();在本地文件上出现“拒绝远程主机文件访问”的错误?

27

我正在使用Tcpdf模块和PHP创建动态PDF发票,该发票来自一个订单系统。

脚本应将发票保存到名为“invoices”的文件夹中。该文件夹已存在,并且“everyone”(Windows)都有完全权限。

我正在使用的代码如下:

$pdf->Output('invoices/Delivery Note.pdf', 'F');

这里使用fopen保存文件。

然而,我遇到的错误是:警告:fopen():不支持远程主机文件访问,file://invoices/Delivery Note.pdf

这是一个本地文件,不是远程文件。

我试图像这样添加一个 / 前缀:

$pdf->Output('/invoices/Delivery Note.pdf', 'F');

然而我收到了这个错误信息:警告:fopen(file:///invoices/Delivery Note.pdf):无法打开流:没有那个文件或目录

我创建了文件,并将其保留为空,但出现了与上述相同的错误。

有人知道我为什么会收到这个错误吗?

8个回答

42

您可以从php脚本中使用:

$pdf->Output(__DIR__ . '/invoices/Delivery Note.pdf', 'F');

这是一个比被选中的答案更好的答案,因为它在更新TCPDF后仍然可以工作。谢谢! - jrgd
虽然我同意在tcpdf_static.php中注释掉代码是一个不好的想法,但我认为相对于指定脚本位置的输出位置,相对于DOCUMENT_ROOT指定输出位置是一个更好的想法。不过这两种方法差别不大,我猜。 - JamesG

9

在vtiger 6.2中升级到tcpdf 6.2.6后,我遇到了同样的问题,即发送带有pdf的电子邮件。

因此,我已经更改了文件:

 libraries/tcpdf/include/tcpdf_static.php

我已经在fopenLocal()函数中添加了注释,并更改了该行代码

 fopen($_SERVER['DOCUMENT_ROOT'].$filename, $mode);

请查看:

  /**
         * Wrapper to use fopen only with local files
         * @param filename (string) Name of the file to open
         * @param $mode (string) 
         * @return Returns a file pointer resource on success, or FALSE on error.  
         * @public static
         */
        public static function fopenLocal($filename, $mode) {
    //      if (strpos($filename, '://') === false) {
    //          $filename = 'file://'.$filename;
    //      } elseif (strpos($filename, 'file://') !== 0) {
    //          return false;
    //      }
            return fopen($_SERVER['DOCUMENT_ROOT'].$filename, $mode);
        }

更改后,它可以正常工作。

你不需要在tcpdf_static.php中注释掉代码,因为提供一个带有绝对路径名的文件名(DOCUMENT_ROOT会给你)就足够了。 - JamesG
可行的解决方案! - mirushaki
两年后,你救了我的一天!谢谢! - Adrian P.

5
user1007017类似,只需按如下所示的方式注释掉该行代码(tcpdf 6.2.11)
public static function fopenLocal($filename, $mode) {
        if (strpos($filename, '://') === false) {
            //$filename = 'file://'.$filename;
        } elseif (stream_is_local($filename) !== true) {
            return false;
        }
        return fopen($filename, $mode);
    }

您真是个救命恩人,即使这么多年过去了!我花了好几个小时试图解决这个问题。您的解决方案完美地解决了我的问题。我还得使用@gerd的__DIR__解决方案,但现在一切都正常了... - Woody

4
我建议您像Gerd建议的那样使用以下代码,但请确保使用绝对路径:$pdf->Output(__DIR__ . '/invoices/Delivery Note.pdf', 'F'); 路径必须是绝对路径而不是相对路径。这个PHP bug报告解释了原因:https://bugs.php.net/bug.php?id=28820。相对路径不受file://包装器支持的原因在于如何处理UNC路径(更具体地说,如何模糊地将“/”解释为Windows安装中的“\”)。例如:file://foo/bar 可以被解释为当前工作目录中的相对URI:foo/bar,也可以被解释为UNC:\foo\bar(计算机foo上的共享bar)。出于这个原因和一些内部原因,当显式调用时,文件://包装器限制为绝对路径。对于相对路径,可以使用realpath() {就像您在报告中所做的那样},或者省略文件包装器的显式命名。
您可以避免修改TCPDF代码并担心任何升级替换您修改的代码。

0
在 PrestaShop 中,您可以这样做:$pdf->Output(_PS_ROOT_DIR_.'/modules/xxx/ticket.pdf', 'F');

0
我发现问题在于fopen的路径必须来自文档根目录,而不是PHP脚本位置。

C:\Website\www\script\invoice\invoice.pdf

例如,如果PHP脚本位于“script”文件夹中,而您想要在“invoice”文件夹中创建PDF,则脚本需要具有“\ script \ invoice \ invoice.pdf”。

0
你可以使用这个脚本
'$'pdf->Output(dirname(FILE,2). '/invoices/Delivery Note.pdf', 'F');

$pdf->Output(dirname(FILE,2). '/invoices/Delivery Note.pdf', 'F'); - liamsi hafil
你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的回答是否正确。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

-2

试试这个

$pdf->Output($_SERVER['DOCUMENT_ROOT'].'/invoices/Delivery Note.pdf', 'F');

1
仍然是相同的错误:警告:fopen(file://E:/Websites/*******/www/invoices/Delivery Note.pdf):无法打开流:没有那个文件或目录 - user2924019
echo $_SERVER['DOCUMENT_ROOT'].'/invoices/Delivery Note.pdf' then hit printed url in your window explorer and check you get file or not. - Navjot Singh
我也使用了相同路径的touch()函数来创建一个空文件,它可以工作,但是fopen仍然无法访问它。 - user2924019
我在阅读这篇文章之前就尝试过这种方法,但它并没有起作用。 - edisonmecaj

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