Youtube API yoluyla büyük video yükleme Bellek yetersiz neden

4 Cevap php

Ben Youtube Direct Upload üzerinden video göndermek için PHP kullanıyorum. Daha küçük ölçekli videoları için çalışıyor ancak bir 390 MB video göndermek için çalışırken, ben şu hatayı alıyorum:

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

I memory_limit artan denedim ama yardımcı olmuyor.

    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;

Ben de exec() ile kıvırın çalışıyor denedim ama sonra daha da garip şeyler oluyor:

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

Ben yüklemek için veri dosyasını kaydettiğiniz nerede / tmp / youtube.xml olduğunu. Belki de bu kullanım yanlıştır?

Dosya gönderilen ancak daha sonra boş bir cevap almak gibi görünüyor bu yüzden bu yaklaşık 6 dakika sürecek:

% 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

EDIT:

Ben bu yüzden bunun için normal bir PHP API kütüphanesi kullanamazsınız OAuth kullanıyorum. I outlined here olarak XML dosyasında yer videonun ikili veri ile bir XML dosyası yüklemeniz gerekir

I found another person with the same problem kim okumak ve parçalar dosya göndermek için kod temin vardı. Bu yöntemi deneyerek Ancak, Youtube "Content-Length" başlığı gerekli olduğunu söyleyen bir 411 sayfa dönecekti. Ben bu yüzden bu bir hata olabilir içerik-uzunluk başlığı kuruyorum. Bu yöntem, fsockopen() işlevini yerine cURL kullanır. [Aslında, yine koduna bakarak, ben sadece yerine "\ n" ile başlıklarını ayıran olduğunu fark "\ r \ n." Bu sorun olabilir. Ben satırbaşları ile deneyin yanı] olacaktır

Edit 2:

Ben "\ r \ n" çalıştı düşünüyorum, ama şimdi kodu ile, tekrar Youtube boş bir yanıt alıyorum.

Herhangi Curl bana bu çalışma almak yardımcı olabilir orada uzmanlar? Ben tamamen bu tarafından stumped.

4 Cevap

Göndermeden önce belleğe tüm dosyayı okumak için değil deneyin. kıvırmak IMHO yüklemeden önce dosyayı kendisi okuma destekler ve bunun bellek sınırları içinde çalışması gerekir. Örnek için aşağıdaki blog yazısı bakınız: http://dtbaker.com.au/random-bits/uploading-a-file-using-curl-in-php.html

Ben henüz youtube doğrudan upload API ile çalıştı değil ama hızlı bir bakıştan sonra ben bu görünmüyor gördüm normal bir html form dosyası yükleme olacak ama biraz daha karmaşık veri formatı. Ben bellekte kendinizi bütün POST verileri bina olmadan düz cURL ile yapabilirsiniz emin değilim.

Geçici bir dosya oluşturun ve fwrite kullanarak bu dosya tanıtıcısı ((içine POST isteği veri yazmak: Eğer bu küçük bellek sınırlarını (RAM ~ 4 MB) varsa PHP akarsu API üstüne kendi basit bir HTTP istemcisi bina deneyebilirsiniz ) Normal dizeleri ve veri dosya transferi doğrudan dosya için stream_copy_to_stream ()) için. İsteğiniz hazır olduğunda, başına geçici dosyasını geri sarmak ve sonra (yine stream_copy_to_stream kullanarak ()) youtube http sunucu ile bağlantı içine akışı kopyalamak.

Akışları, küçük parçalar halinde kopyalanmış gibi hatta büyük dosyalar için, RAM az sonra 4 MB ile bunu yapmak mümkün olmalıdır.

EDIT:

Pseudo-php-code-mashup aşağıdaki ;) yardımcı olmalı

$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...

Orada bir sürü böcek, bu kod kesinlikle vardır ama bu sadece kısa bir örnek olarak biz bununla yaşayabiliriz düşünüyorum. ;)

Bunu deneyin:

ini_set('memory_limit', -1);

İşe yarıyor mu?

Nasıl hakkında

$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);

Bu benim bunu uygulamak için kullanılan kod:

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];
}