Скачать ZipArchive OutOfMemory - PullRequest
       14

Скачать ZipArchive OutOfMemory

0 голосов
/ 25 сентября 2018

У меня проблема с загрузкой файла в мое приложение heroku.У меня есть базовый PHP ini, который позволяет нам иметь 128 МБ для ограничения памяти.

Моя ошибка заключается в следующем:

(1/1) OutOfMemoryException Ошибка: допустимый объем памятииз 134217728 байт исчерпано (попытался выделить 77709312 байт)

Хорошо, я понял, но странная вещь - 77709312bytes только 74 МБ.

Так что же не так?Вот код моего действия загрузки:

/**
 * @Route("/templates/{id}/download", name="api_templates_download", requirements={"id"="\d+"})
 * @Method({"GET"})
 * @param \Symfony\Component\HttpFoundation\Request $request
 * @return \Symfony\Component\HttpFoundation\Response
 * @throws \Exception
 */
public function downloadTemplate(Request $request)
{
    $id = $request->get('id');

    try {
        $template = $this->service->getTemplate($id, $this->helper->getUser());
        $archive = $this->service->downloadTemplate($template);
        $response = new Response(file_get_contents($archive));
        $response->headers->set('Content-Type', 'application/zip');
        $response->headers->set('Content-Disposition', 'attachment;filename="' . $archive . '"');
        $response->headers->set('Content-length', filesize($archive));

        return $response;
    } catch (\Exception $e) {
        $response = new Response(json_encode($e->getMessage()), 401);
        $response->headers->set('Content-Type', 'application/json');
        return $response;
    }
}

И метод downloadTemplate, вызываемый в контроллере:

/**
 * @tests Need to tests about performance - do this in september with real server
 * @param \App\Domain\Dollycast\Template\Entity\Template $template
 * @return string
 */
public function downloadTemplate(Template $template)
{
    $zip = new \ZipArchive();
    $zipName = self::ZIPDIR . $template->getName() . '.zip';

    $zip->open($zipName, \ZipArchive::CREATE);

    $finder = new Finder();
    $finder->files()->in(self::WORKDIR . $template->getName());

    $zip->addEmptyDir($template->getName());
    /** @var SplFileInfo $file */
    foreach ($finder as $file) {
        // Rename the full path to the relative Path
        $zip->addFile(
            self::WORKDIR . $template->getName() . DIRECTORY_SEPARATOR . $file->getRelativePathname(),
            $template->getName() . DIRECTORY_SEPARATOR . $file->getRelativePathname()
        );
    }

    $zip->close();

    return $zipName;
}

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

file_get_contents загрузит файл в память, когда я помещу это в объект Response, это эффективно скопирует весь контент из памяти в выходной буфер.Вот почему архив с размером 74MB приведет к ошибке Out of memory для конфигурации 128M (74 * 2) из-за двойной работы.

В настоящее время я не могу использовать readfile() длярешить эту проблему, потому что поведение слишком сильно отличается для моих нужд.Но readfile() откроется и выведет в буфер без использования двойной памяти.

РЕДАКТИРОВАТЬ: Лучшая альтернатива, которую я нашел, - это использование объекта BinaryFileResponse из Symfony 3.2, который эффективно обрабатывает поток ответа.

0 голосов
/ 25 сентября 2018

Вы пробовали file_get_contents($zipName); unlink($zipName);, чтобы вы могли удалить файл с локального

0 голосов
/ 25 сентября 2018

(1/1) OutOfMemoryException Ошибка: допустимый объем памяти 134217728 байт исчерпан (попытка выделить 77709312 байт)

В то время, как процесс php пытается выделить 77709312 байтуже выделена память, что можно проверить с помощью функции memory_get_usage ().В вашем случае это должно быть больше (134217728 - 77709312 =) 56508416 байт.

Если исключение возникает при создании файла zip, вы можете попробовать использовать внешний инструмент для создания файла zip.Что-то вроде

exec ("tar -zcvf archive.tar.gz / folder / tozip");

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

...