3

PHPを使用して、ダイレクトアップロード経由でYouTubeにビデオを送信しています。小さいサイズのビデオでは問題なく動作しますが、390 MB のビデオを送信しようとすると、次のエラーが発生します。

PHP 致命的なエラー: メモリ不足 (割り当てられた 3932160) (390201902 バイトを割り当てようとしました)

増やしてみまし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;

curl も実行してみましexec()たが、さらに奇妙なことが起こります。

curl http://uploads.gdata.youtube.com/feeds/api/users/default/uploads -H 'POST /feeds/api/users/default/uploads HTTP/1.1' -H 'ホスト: 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 =[中略]' -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 ファイルに含まれる動画のバイナリ データを含む XML ファイルをアップロードする必要があります。

ファイルをチャンクで読み取って送信するためのコードを提供した、同じ問題を抱えた別の人を見つけました。ただし、この方法を試すと、Youtube は「Content-Length」ヘッダーが必要であることを示す 411 ページを返します。content-length ヘッダーを設定しているので、これはバグである可能性があります。このメソッドは、fsockopen()cURL の代わりに関数を使用します。[実際、コードをもう一度見てみると、ヘッダーを「\r\n」ではなく「\n」で区切っていただけであることに気付きました。それが問題かもしれません。キャリッジリターンも試してみます]

編集2:

「\r\n」は機能したと思いますが、コードを使用すると、YouTube から空の返信が再び届きます。

これを機能させるのに役立つ Curl の専門家はいますか? 私はこれに完全に困惑しています。

4

4 に答える 4

3

送信する前に、ファイル全体をメモリに読み込まないようにしてください。curl IMHOは、アップロード前のファイル自体の読み取りをサポートしているため、メモリ境界内で機能する必要があります。例については、次のブログ投稿を参照してください。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()、ファイルからファイルへの直接データ転送の場合はstream_copy_to_stream())。リクエストの準備ができたら、一時ファイルを最初に巻き戻し、そのストリームをyoutube httpサーバーとの接続にコピーします(ここでもstream_copy_to_stream()を使用します)。

ストリームは小さなチャンクでコピーされるため、大きなファイルの場合でも、4MB未満のRAMでそれを実行できるはずです。

編集:

次のpseudo-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...

このコードには確かに多くのバグがありますが、それはほんの短い例であるため、私たちはそれで生きることができると思います。;)

于 2010-01-24T18:51:26.840 に答える
0

どうですか

$filename = "--REMOTE FILE--";
$localfile = "/storage/local.flv";

$handle = fopen($filename, "r");

while ($contents = fread($handle, 10485760)) { // thats 10 MB

$localhandle = fopen($localfile, "a");
fwrite ($localhandle, $contents);
fclose($localhandle);

}

fclose($handle);
于 2010-01-24T08:28:57.307 に答える
0

やってみてください:

ini_set('memory_limit', -1);

それは機能しますか?

于 2010-01-24T07:49:40.233 に答える
0

これは、これを実装するために使用したコードです。

public function uploadVideo(Model_Row_Video $video)
{
        $request = $this->getOAuthRequest(self::URL_UPLOAD, 'POST');

        $boundary = 'RANDOM BOUNDARY STRING';

        $videoFile = $video->getAbsolutePath();
        $contentType = $this->getContentType($videoFile);

        $xml = $this->getAtom($video);
        $data = <<<EOD
--{$boundary}
Content-Type: application/atom+xml; charset=UTF-8

{$xml}
--{$boundary}
Content-Type: {$contentType}
Content-Transfer-Encoding: binary\r\n\r\n
EOD;
        $footer = "\r\n--{$boundary}--\r\n";

        $pdh = tmpfile();
        fwrite($pdh, $data);
        $f_video = fopen($videoFile, "r");
        stream_copy_to_stream($f_video, $pdh);
        fclose($f_video);
        fwrite($pdh, $footer);

        $info = fstat($pdh);

        $headers = array(
            "POST /feeds/api/users/default/uploads HTTP/1.1",
            'Host: uploads.gdata.youtube.com',
            $request->to_header(),
            'GData-Version: 2',
            'X-GData-Client: ' . self::CONSUMER_KEY,
            'X-GData-Key: key=' . self::DEVELOPER_KEY,
            'Slug: ' . $video['local'],
            'Content-Type: multipart/related; boundary="' . $boundary . '"',
            'Content-Length: ' . $info['size'],
            'Connection: close'
        );

        $headers_str = implode("\r\n", $headers) . "\r\n\r\n";
        rewind($pdh);

        $conn = fsockopen('uploads.gdata.youtube.com', 80, $errno, $errstr, 30);
        fputs($conn, $headers_str);
        stream_copy_to_stream($pdh, $conn);

        $return = '';
        while (!feof($conn)) {
            $return .= fgets($conn, 128);
        }

        fclose($conn);

        echo "errno: $errno\n";
        echo "errstr: $errstr\n";
        $out = strstr($return, '<?xml');

        $xml = simplexml_load_string($out);

        if (!$xml) {
            echo $out;
        }

        $xml->registerXPathNamespace('yt','http://gdata.youtube.com/schemas/2007');
        $id = $xml->xpath('//yt:videoid');

        return $id[0];
}
于 2013-06-20T00:40:15.560 に答える