Intereting Posts
Печать повернутого текста с веб-страницы Как создать двухсторонние методы кодирования / декодирования с использованием специального ключа – PHP? Проблема при загрузке php-файла в переменную (Загрузить результат php-кода вместо кода в виде строки) Загрузка PHP – Почему isset ($ _ POST ) всегда FALSE CakePHP3 пользовательский метод поиска, содержащий и не работает при попытке отобразить связанное поле модели php / mysql: база данных банковских праздников и событий, таких как Рождество, Пасха и т. д. Проверка доступности AJAX с кнопкой отправки Как вы указываете предложение IN в динамическом запросе с использованием переменной? Как контролировать активность пользователя на моем веб-сайте? Как заставить переменные сеанса сохраняться в перенаправлении заголовков? Mongodb PHP-драйвер: как создать базу данных и добавить к ней пользователя? Изменить язык по ссылке сделать временную таблицу и выбрать ее Отправлять html и текстовое сообщение одновременно с PHP Mailer переменные переменные

Загрузка большого видео через Youtube API, вызывающий нехватку памяти

Я использую PHP для отправки видео через прямую загрузку на Youtube. Он отлично работает для видео меньшего размера, но при попытке отправить 390 МБ видео я получаю следующую ошибку:

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 'Host: uploads.gdata.youtube .com '-H' Авторизация: 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; border = "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, поэтому я не могу использовать обычную библиотеку API PHP для этого. Я должен загрузить файл XML с бинарными данными видео, включенными в XML-файл, как описано здесь

Я нашел другого человека с той же проблемой, который предоставил код для чтения и отправки файла в куски. Однако при попытке этого метода Youtube вернет страницу 411, в которой требуется заголовок «Content-Length». Я устанавливаю заголовок длины содержимого, чтобы это могло быть ошибкой. Этот метод использует fsockopen() вместо cURL. [На самом деле, снова взглянув на код, я понимаю, что просто разделял заголовки с помощью «\ n» вместо «\ r \ n». Это может быть проблемой. Я также попробую с возвратом каретки]

Изменить 2:

Я думаю, что «\ r \ n» работал, но теперь с кодом, я снова получаю пустой ответ от Youtube.

Какие-нибудь эксперты Curl, которые могут помочь мне получить эту работу? Я полностью в шоке от этого.

Старайтесь не читать весь файл в памяти перед отправкой. curl IMHO поддерживает чтение самого файла перед загрузкой и поэтому должен работать внутри границ памяти. Для примера см. Следующее сообщение в блоге: http://dtbaker.com.au/random-bits/uploading-a-file-using-curl-in-php.html

Я еще не работал с API прямой загрузки youtube, но после быстрого просмотра я увидел, что это не похоже на обычную загрузку файла формы html, но немного более сложный формат данных. Я не уверен, можете ли вы сделать это с помощью простой cURL, не строя все данные POST в памяти самостоятельно.

Если у вас есть небольшие пределы памяти (~ 4 МБ ОЗУ), вы можете попытаться создать свой собственный простой HTTP-клиент поверх API потоков в PHP: создать временный файл и записать данные запроса POST в этот дескриптор файла (используя fwrite ( ) для обычных строк и stream_copy_to_stream () для прямого переноса файлов на файл). Когда ваш запрос будет готов, перемотайте свой временный файл в начало и затем скопируйте этот поток в соединение с http-сервером youtube (снова используя stream_copy_to_stream ()).

Поскольку потоки копируются небольшими фрагментами, вы должны иметь возможность делать это с объемом памяти менее 4 МБ, даже для больших файлов.

РЕДАКТИРОВАТЬ:

После использования псевдо-php-кода-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... 

В этом коде есть много ошибок, но, поскольку это всего лишь короткий пример, я думаю, что мы сможем жить с этим. 😉

Попробуйте сделать:

 ini_set('memory_limit', -1); 

Это работает?

Как насчет

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

Это код, который я использовал для реализации этого:

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