Временный файл

oracloid

совсем кукус
Временный файл

Задача такая: для экономии оперативки я перехватываю всю выдачу скрипта и скидываю порциями в файл, очищая при этом буфер. В конце работы файл надо выдать пользователю. Файлы могут получаться большими (> 100 Мб).

Я вначале сделал работу с файлом через tmpfile(), чтобы не парицо в случае фатальных ошибок скрипта. Возникновение таких ошибок я не могу отследить, т.к. используются лямбда-функции, и что там в них за код неизвестно (он не мой). То есть у меня бывают ошибки парсинга, которые не может перехватить set_error_handler().

В случае успеха я отдаю файл так:
PHP:
fseek($this->swap_handle, 0);
echo fread($this->swap_handle, $this->swap_size);
И вот это echo мне очень не нравится!
В данном случае файл будет сначала зачитан в память, во временную переменную, и только потом выдан stdout.

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

Просто тупо делать foreach( glob() ) @unlink()? Открытые файлы не удалятся...

Какие есть мысли?
 
Большие отчеты (десятки Мб), и различные выгрузки данных в разных форматах. Мне нужно чтобы их формирование не пожирало ресурсы, т.к. эти процессы запускаются параллельно в большом количестве.
 
При параллельной работе скриптов (в большом количестве) с данными такого объема ресурсы будут пожираться всегда. Вообще, PHP для решения подобной задачи выбран не совсем удачно.. Либо задача поставлена некорректно.
 
Yuriy_S
PHP прекрасно справляется, и кушает немного.
Самое узкое звено - выходной буфер.

CHEM_Eugene
ты не в теме
 
oracloid
Возникновение таких ошибок я не могу отследить, т.к. используются лямбда-функции, и что там в них за код неизвестно (он не мой). То есть у меня бывают ошибки парсинга, которые не может перехватить set_error_handler().
А это как? Вроде-бы ошибка парсинга скрипта либо есть, либо ее нет, или она может быть плавающей?

Какие есть мысли?
Поставь перед этими скриптами nginx и он будет заниматься буферизацией ответов. В случае если в скрипте выскочит что-то типа parser error'а, то можно сделать так что php выдаст к примеру 500-й код ошибки, а nginx увидев это может отдать пользователю какую-либо страницу с нормальным сообщением об ошибке.
 
phprus
А это как? Вроде-бы ошибка парсинга скрипта либо есть, либо ее нет, или она может быть плавающей?
Говорю ж - анонимные функции - обработчики событий, которые создаются в рантайме. В них может быть вообще все, что угодно.

Поставь перед этими скриптами nginx и он будет заниматься буферизацией ответов.
Думал об этом. Но не могу этого сделать, т.к. все это крутится на сервере приложений Oracle, и там уже перед апачем стоит их webcache, их связку хрен разорвешь, они и апач переписали.
Да и потом, на своем сервере я может и сделал бы это, но система разворачивается у наших заказчиков (их много), у них разные платформы, и ваще я тогда работать перестану, только и буду эти прокси настраивать всем :)
 
oracloid
Говорю ж - анонимные функции - обработчики событий,
Если анонимные функции создаются через create_function, то она в случае если не может создать функцию с таким кодом просто возвращает false и печатает ошибку:
PHP Parse error: * in ** : runtime-created function on line ***. Никакого прекращения работы всего скрипта не происходит.

я тогда работать перестану
А ты так и так работать перестанешь, так как костылестроение очень быстро сделает проект полностью не поддерживаемым. И с ростом числа существующих костылей потребность в новых костылях будет очень быстро возрастать.

Кстати можешь посмотреть на http://ru2.php.net/manual/ru/runkit.sandbox.php
 
phprus
если не может создать функцию с таким кодом просто возвращает false
Спасибо, в мануале об этом нет ни слова! (который в виде chm файла).
Но в любом случае там может быть любая бяка, вплоть до деления на ноль :)

Твою мысль про костылестроение не очень понял. Я описал не костыль, а фичу, которая очень экономит оперативку. А вся проблема из-за недостаточно полной реализации обработки исключений в языке. Если бы только set_error_handler() отлавливала все уровни ошибок! Ну и readfile() тоже хороша: могла бы принимать в качестве параметра хендл открытого файла :D

Напоминаю тему топика: как удалить временный файл в случае аварийного завершения скрипта, или, если этого сделать нельзя, то как лучше организовать зачистку?
При чем тут Runkit_Sandbox?
 
Автор оригинала: oracloid
как удалить временный файл в случае аварийного завершения скрипта, или, если этого сделать нельзя, то как лучше организовать зачистку?
это? http://ru2.php.net/manual/en/function.register-shutdown-function.php

Код:
register_shutdown_function(create_function("","echo '!!!!!!!!!!!!!!Fuck';"));

throw new Exception("Hello");

->

<br />
<b>Fatal error</b>:  Uncaught exception 'Exception' with message 'Hello' in PHPDocument2:5
Stack trace:
#0 C:\Program Files\Zend\ZendStudio-5.5.1\bin\php5\dummy.php(1): include()
#1 {main}
  thrown in <b>PHPDocument2</b> on line <b>5</b><br />
!!!!!!!!!!!!!!Fuck

-~{}~ 23.07.08 14:59:

в общемто соглашусь с тобой что ошибки реализованны через попу (это историческая проблема). Те надо либо полнстью переходить на исключения (с доработкой finally) либо полностью переходить на обычные ошибка (trigger_error). Потому-что эта мешанина (из-за большого кол-ва разработчиков: кому-то нравится обьектный подход, кому-то процедурный - каждый городит своё). Лично мне ближе исключения, гораздо более удобный (привычный) способ
 
kode, спасибо! Я про эту функцию совершенно забыл! :)
тему можно закрывать.

-~{}~ 23.07.08 15:10:

tony2001
Я tmpfile() и использовал сначала, но мне не надо удалять файл при fclose(), т.к. я его потом хочу выдать с помощью readfile().
Ты почитай первое сообщение.
 
не надо его закрывать fclose().
вместо readfile() можно использовать fpassthru(), ты перечитай мануал.
 
oracloid
Твою мысль про костылестроение не очень понял.
Обертки заставляющие это:
Возникновение таких ошибок я не могу отследить, т.к. используются лямбда-функции, и что там в них за код неизвестно (он не мой). То есть у меня бывают ошибки парсинга, которые не может перехватить set_error_handler().
работать это костыли. Нормальный код при своей работе не должен вызывать ошибок, а попытка замаскировать всплывающие ошибки чем-либо это и есть костыли.

Ну и readfile() тоже хороша: могла бы принимать в качестве параметра хендл открытого файла
Есть [m]fpassthru[/m].

как удалить временный файл в случае аварийного завершения скрипта
Аварийного завершения скрипта быть не должно. Ошибки должны обрабатываться штатно.

При чем тут Runkit_Sandbox?
При том, что тебе не удаление временных файлов при ошибке нужно делать, а запускать потенциально ошибочный код в отдельной песочнице, которая на основной код повлиять никак не может.
 
tony2001
вот оно, то что было нужно для полного счастья! :D
спасибо!!!

-~{}~ 23.07.08 15:25:

phprus
При том, что тебе не удаление временных файлов при ошибке нужно делать, а запускать потенциально ошибочный код в отдельной песочнице, которая на основной код повлиять никак не может.
Спасибо, пошел читать!

-~{}~ 23.07.08 15:28:

phprus
еще вопрос: а эта песочница полностью изолирована, или из нее можно работать с объектами основного скрипта?
 
oracloid
еще вопрос: а эта песочница полностью изолирована, или из нее можно работать с объектами основного скрипта?
А вот этого я не знаю. Я с ней не работал, так как у меня пока что не было задачь которые требовали-бы выполнять потенциально ошибочный и опасный код. Но судя по ману ей можно передать объекты из основной программы, а так-же из основной программы можно получать доступ к переменным, которые находятся внутри песочницы.
 
phprus
Да, я уже нашел, там у объекта есть свойства, которые управляют доступом к объектам родителя.
Жалко только, что это PEAR, причем пакет довольно старый.

Но в принципе, ошибки в рантайм-функциях могут возникать только на этапе разработки конкретного отчета. На этапе пром.эксплуатации они уже будут отлажены.
Пожалуй, оставлю как есть.
(Обработчики вызываются на разные события построения отчета, например, в датасетах при проходе по записям, при всяких инициализациях и т.п.)
 
Сверху