php - 通过 Youtube API 上传大视频导致内存不足

标签 php memory-management curl youtube-api

我正在使用 PHP 通过直接上传将视频发送到 Youtube。它适用于较小尺寸的视频,但在尝试发送 390 MB 视频时,出现以下错误:

PHP Fatal error: Out of memory (allocated 3932160) (tried to allocate 390201902 bytes)

我试过增加 memory_limit 但这没有帮助。

    if ($isFile) {
        ini_set('memory_limit', '2G')
        $data = file_get_contents($data);
    }

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

    $out = curl_exec($ch);
    curl_close($ch);

    return $out;

我还尝试通过 exec() 运行 curl,但随后发生了更奇怪的事情:

curl http://uploads.gdata.youtube.com/feeds/api/users/default/uploads -H 'POST /feeds/api/users/default/uploads HTTP/1.1' -H 'Host: uploads.gdata.youtube.com' -H 'Authorization: OAuth [snip oauth info]"' -H 'GData-Version: 2' -H 'X-GData-Client: www.mywebsite.com' -H 'X-GData-Key: key=[snip]' -H 'Slug: video.AVI' -H 'Content-Type: multipart/related; boundary="iUI5C0hzisAHkx9SvaRJ"' -H 'Content-Length: 390193710' -H 'Connection: close' -d /tmp/youtube.xml

/tmp/youtube.xml 是我保存要上传的数据文件的地方。也许这种用法是错误的?

这大约需要 6 分钟,所以看起来文件正在发送,但随后我收到一个空回复:

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                Dload  Upload   Total   Spent    Left  Speed

 0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
 0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
 ...
 0     0    0     0    0     0      0      0 --:--:--  0:06:00 --:--:--     0
curl: (52) Empty reply from server

编辑:

我正在使用 OAuth,所以我不能为此使用普通的 PHP API 库。我必须上传一个 XML 文件,其中包含视频的二进制数据作为 outlined here

found another person with the same problem谁提供了代码来分块读取和发送文件。但是,在尝试此方法时,Youtube 会返回一个 411 页面,指出需要“Content-Length” header 。我正在设置内容长度 header ,所以这可能是一个错误。此方法使用 fsockopen() 函数而不是 cURL。 [实际上,再次查看代码,我意识到我只是用“\n”而不是“\r\n”分隔 header 。这可能是问题所在。我也会尝试回车]

编辑 2:

我认为“\r\n”有效,但现在有了代码,我再次收到来自 Youtube 的空回复。

有没有 Curl 专家可以帮助我完成这项工作?我完全被这个难住了。

最佳答案

尽量不要在发送前将整个文件读入内存。 curl 恕我直言支持在上传之前读取文件本身,因此应该在内存边界内工作。有关示例,请参阅以下博客文章:http://dtbaker.com.au/random-bits/uploading-a-file-using-curl-in-php.html

我还没有使用过 youtube 直接上传 API,但快速浏览后我发现这似乎不是普通的 html 表单文件上传,而是一种更复杂的数据格式。我不确定您是否可以在不自己在内存中构建整个 POST 数据的情况下使用普通 cURL 执行此操作。

如果您有这么小的内存限制(~4 MB RAM),您可以尝试在 PHP 中的流 API 之上构建您自己的简单 HTTP 客户端:创建一个临时文件并将您的 POST 请求数据写入该文件句柄(使用 fwrite() 用于普通字符串和 stream_copy_to_stream() 用于直接文件到文件数据传输)。当您的请求准备就绪时,将您的临时文件倒回到开头,然后将该流复制到与 youtube http 服务器的连接中(再次使用 stream_copy_to_stream())。

由于流是以小块的形式复制的,因此您应该能够使用少于 4 MB 的 RAM 来执行此操作,即使对于大文件也是如此。

编辑:

以下伪 php-code-mashup 应该会有帮助;)

$xmlAPIRequest = /* fill with the XML-API-Request */
$boundaryString = /* fill me with some random data */

// create temporary file handle
$pdh = tmpfile();
fwrite($pdh, "--$boundaryString\r\n");
fwrite($pdh, "Content-Type: application/atom+xml; charset=UTF-8\r\n\r\n");
fwrite($pdh, $xmlAPIRequest."\r\n");
fwrite($pdh, "--$boundaryString\r\n");
fwrite($pdh, "Content-Type: <video_content_type>\r\nContent-Transfer-Encoding: binary\r\n\r\n");

$videoFile = fopen("/path/to/video", "r");
stream_copy_to_stream($videoFile, $pdh);
fclose($videoFile);

fwrite($pdh, "--$boundaryString--\r\n");
/* not quite sure, whether there needs to be another linebreak before the boundary string */

$info = fstat($pdh);
rewind($pdh);

$contentLength = $info['size'];

$conn = fsockopen("hostname", 80);
/* write http request to $conn and use $contentLength for Content-Length header */
/* after last header you put another line break to tell them that now the body follows */

// write post data from stream to stream
stream_copy_to_stream($pdh, $conn);

// ... process response... etc...

这段代码中肯定有很多错误,但由于这只是一个简短的例子,我认为我们可以接受。 ;)

关于php - 通过 Youtube API 上传大视频导致内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2126330/

相关文章:

c++ - ssl 对等证书或 ssh 远程 key 不正确 - C

php - 在 WHERE 语句中使用相同的列名,使用 "AND"而不是 "OR"

php - 使用其中一个值插入两个 SQL 表

php - 想要升级我用 mysql* 编写的数据库类。接下来我应该使用什么?

PHP/mysql,使用外键从另一个表中获取数据

c - 如何在不破坏严格别名的情况下在一个 malloc 调用中为数组和结构分配内存?

php - 如何打包 PHP 应用程序\脚本?

当通过管道传送到 head 命令时,curl 给出错误

javascript - 使用 javascript 进行高效的实时 SVG 实体管理

ios - 我有内存泄漏吗?