我的服务器上运行了一个文件上传脚本,它还具有远程上传功能..一切正常,但我想知道通过URL上传的最佳方式是什么。现在我正在使用fopen
从名为"的文本框中粘贴的远程URL获取文件;来自"。我听说fopen不是最好的方法。那是为什么?
此外,我使用file_get_contents从URL获取文件的文件大小。我听说curl
在那方面更好。为什么这样,以及如何将这些更改应用于此脚本?
<?php
$from = htmlspecialchars(trim($_POST['from']));
if ($from != "") {
$file = file_get_contents($from);
$filesize = strlen($file);
while (!feof($file)) {
$move = "./uploads/" . $rand2;
move_upload($_FILES['from']['tmp_name'], $move);
$newfile = fopen("./uploads/" . $rand2, "wb");
file_put_contents($newfile, $file);
}
}
?>
答案 0 :(得分:5)
您可以使用filesize
获取磁盘上文件的文件大小。
file_get_contents
实际上会将文件存入内存,因此$filesize = strlen(file_get_contents($from));
已经获取了该文件,除了查找文件大小外,您只是不做任何事情。您可以替换fwrite
来电file_put_contents
;
请参阅:file_get_contents和file_put_contents 。
当您需要更多访问curl
协议时,会使用 HTTP
。在PHP中使用curl
的StackOverflow有很多问题和示例。
因此我们可以先下载该文件,在本例中我将使用file_get_contents
,获取其大小,然后将该文件放在本地磁盘上的目录中。
$tmpFile = file_get_contents($from);
$fileSize = strlen($tmpFile);
// you could do a check for file size here
$newFileName = "./uploads/$rand2";
file_put_contents($newFileName, $tmpFile);
在您的代码中,您有move_upload($_FILES['from']['tmp_name'], $move);
但$_FILES
仅适用于您拥有<input type="file">
元素的情况,而您似乎没有。
P.S。您可能应该在文件名中列出允许的字符,例如$goodFilename = preg_replace("/^[^a-zA-Z0-9]+$/", "-", $filename)
这通常更容易阅读和更安全。
替换:
while (!feof($file)) {
$move = "./uploads/" . $rand2;
move_upload($_FILES['from']['tmp_name'], $move);
$newfile = fopen("./uploads/" . $rand2, "wb");
file_put_contents($newfile, $file);
}
使用:
$newFile = "./uploads/" . $rand2;
file_put_contents($newfile, $file);
整个文件由file_get_contents
读入,整个文件由file_put_contents
答案 1 :(得分:2)
据我了解你的问题:你想获得一个URL提供的远程文件的文件大小,而你不确定哪种解决方案最好/最快。
首先,在此上下文中CURL
,file_get_contents()
和fread()
之间的最大区别是CURL和file_get_contents()将整个内容放入内存,而fopen()为您提供更多地控制您要读取的文件的哪些部分。我认为fopen()和file_get_contents()在你的情况下几乎是等价的,因为你正在处理小文件而你实际上想要得到整个文件。所以它在内存使用方面没有任何区别。
CURL只是file_get_contents()的大哥。它实际上是一个完整的HTTP客户端,而不是某种简单函数的包装器。
谈论HTTP:不要忘记HTTP比GET和POST更多。为什么不使用资源的元数据检查它的大小之前你甚至得到它?这是HTTP方法HEAD的一个目的。 PHP甚至还带有内置函数来获取标题:get_headers()。它有一些缺陷:它仍然发送一个GET请求,这可能会慢一点,并且它遵循重定向,这可能会导致安全问题。但是你可以通过调整默认上下文来轻松解决这个问题:
$opts = array(
'http' =>
array(
'method' => 'HEAD',
'max_redirects'=> 1,
'ignore_errors'=> true
)
);
stream_context_set_default($opts);
完成。现在您只需获取标题:
$headers = get_headers('http://example.com/pic.png', 1);
//set the keys to lowercase so we don't have to deal with lower- and upper case
$lowerCaseHeaders = array_change_key_case($headers);
// 'content-length' is the header we're interested in:
$filesize = $lowerCaseHeaders['content-length'];
注意: filesize()
将不在http / https流包装器上工作,因为不支持stat()(http://php.net/manual/en/wrappers.http.php)。
这就是它。当然,如果你更喜欢它,你可以achieve the same with CURL。方法是相同的(重新标题)。
以下是使用CURL获取文件及其大小(下载后)的方法:
// Create a CURL handle
$ch = curl_init();
// Set all the options on this handle
// find a full list on
// http://au2.php.net/manual/en/curl.constants.php
// http://us2.php.net/manual/en/function.curl-setopt.php (for actual usage)
curl_setopt($ch, CURLOPT_URL, 'http://example.com/pic.png');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Send the request and store what is returned to a variable
// This actually contains the raw image data now, you could
// pass it to e.g. file_put_contents();
$data = curl_exec($ch);
// get the required info about the request
// find a full list on
// http://us2.php.net/manual/en/function.curl-getinfo.php
$filesize = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
// close the handle after you're done
curl_close($ch);
纯PHP方法:http://codepad.viper-7.com/p8mlOt
使用CURL:http://codepad.viper-7.com/uWmsYB
对于文件大小的格式良好且人类可读的输出,我从Laravel学到了这个神奇的功能:
function get_file_size($size)
{
$units = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB');
return @round($size / pow(1024, ($i = floor(log($size, 1024)))), 2).' '.$units[$i];
}
如果您不想处理所有这些问题,请查看Guzzle。它是一个非常强大且易于使用的库,适用于任何类型的HTTP。