move_uploaded_file() 期望参数 2 是有效路径,给定对象

Posted

技术标签:

【中文标题】move_uploaded_file() 期望参数 2 是有效路径,给定对象【英文标题】:move_uploaded_file() expects parameter 2 to be valid path, object given 【发布时间】:2016-07-30 01:11:16 【问题描述】:

我正在使用 Symfony 2.3 保存通过表单 POST 上传的文件。

这是我在控制器中使用的代码:

$fileDir = '/home2/divine/Symfony/src/App/Bundle/Resources/public/files';

$form['my_file']->getData()->move($fileDir, 'book.pdf');

在水下,Symfony 执行以下代码来移动文件:

move_uploaded_file("/tmp/phpBM9kw8", "/home2/divine/Symfony/src/App/Bundle/Resources/public/files/book.pdf");

公共目录有777个权限。

这是我得到的错误:

"Could not move the file "/tmp/phpBM9kw8" to "/home2/divine/Symfony/src/App/Bundle/Resources/public/files/book.pdf" 

(move_uploaded_file() expects parameter 2 to be valid path, object given)" 

我使用的是 PHP 5.3。

更新:

这是执行 move_uploaded_file() 的代码片段:

// Class: Symfony\Component\HttpFoundation\File\UploadedFile

$target = $this->getTargetFile($directory, $name);

if (!@move_uploaded_file($this->getPathname(), $target)) 

// etc...

$target" 变量在此处创建:

protected function getTargetFile($directory, $name = null) 

// Some error handling here...

    $target = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name));

    return new File($target, false);

$target 变量因此是一个 File 类。它确实有一个 __toString() 方法,继承自 SplFileInfo:

/**
 * Returns the path to the file as a string
 * @link http://php.net/manual/en/splfileinfo.tostring.php
 * @return string the path to the file.
 * @since 5.1.2
 */
public function __toString () 

但不知何故,__toString 方法不起作用。

【问题讨论】:

您可能很清楚,其中一个参数是对象,而不是字符串或不能转换为字符串(即对象没有 __toString() 方法)。顺便说一句,我希望它只是你的开发机器。 777 对于实时环境来说是个坏主意... 是的,错误确实表明第二个参数不是字符串。但我很困惑为什么会这样。在我看来,这绝对是一个字符串。 public/files/'; 需要斜杠。因为它在没有它的情况下被读取为public/filesbook.pdf';,而不是public/files/book.pdf'; 另外,如果您还没有使用有效的编码类型,您还需要一个有效的编码类型。 我正在使用 enctype="multipart/form-data"。添加尾部斜杠没有帮助:Symfony 已经添加了,如果你不这样做。 【参考方案1】:

但不知何故,__toString 方法不起作用

它是“魔法方法”之一,当对象在字符串上下文中使用时会自动调用它——例如,如果你有'foo' . $object

但我认为不应该在这种情况下工作。因为 PHP 是松散类型的,您可以将 anything 传递给 move_uploaded_file。此时不会自动转换为字符串。然后在内部,该函数仅检查参数是否为字符串,但不会尝试将其转换为字符串 - 因为这没有什么意义,它可以是 any 类型的对象,并且无法判断调用 __toString 是否会产生有效的文件路径。


您现在可能想知道,为什么在错误消息中我们确实可以看到路径:

无法将文件“/tmp/phpBM9kw8”移动到“/home2/divine/Symfony/src/App/Bundle/Resources/public/files/book.pdf”

我的猜测是,当组装该错误消息时,会进行字符串连接,因此 __toString 确实在这个特定点被调用。


如果你愿意修改 Symfony 源代码,我认为这应该是一个简单的修复,只要你改变这一行

if (!@move_uploaded_file($this->getPathname(), $target)) 

if (!@move_uploaded_file($this->getPathname(), ''.$target)) 

——然后​​你又遇到了这种情况,__toString 将被调用,因为对象通过将它与一个字符串(一个空的,因为我们不想篡改结果值)连接而转移到一个字符串上下文中。 )


当然,直接修改框架的文件并不是最推荐的处理方式——在下一次更新之后,我们的更改可能会再次丢失。我建议你检查 Symfony bugtracker(他们应该有类似的东西),看看这是否已经是一个已知问题,是否可能存在官方补丁文件;否则将其报告为错误,以便可以在未来的版本中修复。

【讨论】:

谢谢!事实上,__toString() 方法不会自动调用,concat 技巧确实有效。奇怪的是,这段代码过去一直有效。我会检查 bugtracker。

以上是关于move_uploaded_file() 期望参数 2 是有效路径,给定对象的主要内容,如果未能解决你的问题,请参考以下文章

php中函数move_uploaded_file()移动中文文件报错的解决方法

move_uploaded_file() 无法打开流:没有这样的文件或目录

move_uploaded_file() 无法将文件从 tmp 移动到 dir

777 文件夹上的 move_uploaded_file 权限被拒绝

move_uploaded_file 无法打开流:权限被拒绝 - Mac

move_uploaded_file() php 函数不适用于多次上传