Как увеличить timeout php

Как увеличить время выполнения PHP-скрипта?

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

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

 Fatal error: Maximum execution time of 30 seconds exceeded in pandoge_com.php on line 19

Я расскажу о 4-х способах, как избавиться от нее.

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

Увеличение времени выполнения PHP-скрипта через конфигурационный файл php.ini

В качестве первого способа для увеличения времени выполнения скрипта мы будем использовать файл конфигурации php.ini.

Для того чтобы точно узнать, где находится этот файл, прочитайте эту статью.

Открываете его удобным для вас способом и в самый низ вставляете:

Где «300» означает 300 секунд (меняете на свое). Этот файл, к сожалению, не на всех хостингах доступен пользователям для редактирования.

Увеличение времени выполнения PHP-скрипта через встроенную функцию «ini_set»

Второй способ основывается на использовании функции «ini_set». Ее вы вставляете непосредственно в сам файл скрипта, желательно в самый верх. Пример:

Здесь значение «300» вы также сменяете на нужное вам в секундах. Обратите внимание, что при использовании PHP в безопасном режиме эта функция будет недоступна.

Увеличение времени выполнения PHP-скрипта через встроенную функцию «set_time_limit»

Третий способ, наверное, один из самых популярных – использование функции «set_time_limit» для изменения времени выполнения скрипта. Также используется непосредственно в самом файле PHP. Пример:

Здесь «300» вы также изменяете на нужное вам значение. Вставлять код желательно в самом верху.

Увеличение времени выполнения PHP-скрипта через файл .htaccess

Последний вариант заключается в редактировании файла .htaccess, который находится в корне вашего сайта (если таковой отсутствует – создайте его).

В самый верх этого файла вставьте:

 php_value max_execution_time 300

Значение «300» вы также меняете на свое.

Обратите внимание, что во всех случаях время выполнения скрипта указывается в секундах. Помимо этого, значение параметра во всех способах может принимать «0», что означает неограниченное время выполнения.

Читайте также:  You want to do what with php

Как узнать, сколько времени отведено на выполнение PHP-скрипта?

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

Для этого создайте PHP-файл в корне вашего сайта, где выведите значение установленного времени:

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

Источник

set_time_limit

Set the number of seconds a script is allowed to run. If this is reached, the script returns a fatal error. The default limit is 30 seconds or, if it exists, the max_execution_time value defined in the php.ini .

When called, set_time_limit() restarts the timeout counter from zero. In other words, if the timeout is the default 30 seconds, and 25 seconds into script execution a call such as set_time_limit(20) is made, the script will run for a total of 45 seconds before timing out.

Parameters

The maximum execution time, in seconds. If set to zero, no time limit is imposed.

Return Values

Returns true on success, or false on failure.

Notes

Note:

The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system() , stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real.

See Also

User Contributed Notes 25 notes

Both set_time_limit(. ) and ini_set(‘max_execution_time’. ); won’t count the time cost of sleep,file_get_contents,shell_exec,mysql_query etc, so i build this function my_background_exec(), to run static method/function in background/detached process and time is out kill it:

my_exec.php:
function my_background_exec ( $function_name , $params , $str_requires , $timeout = 600 )
< $map =array( '"' =>‘\»‘ , ‘$’ => ‘\$’ , ‘`’ => ‘\`’ , ‘\\’ => ‘\\\\’ , ‘!’ => ‘\!’ );
$str_requires = strtr ( $str_requires , $map );
$path_run = dirname ( $_SERVER [ ‘SCRIPT_FILENAME’ ]);
$my_target_exec = «/usr/bin/php -r \»chdir(‘ < $path_run >‘); < $str_requires >\\\$params=json_decode(file_get_contents(‘php://stdin’),true);call_user_func_array(‘ < $function_name >‘, \\\$params);\»» ;
$my_target_exec = strtr ( strtr ( $my_target_exec , $map ), $map );
$my_background_exec = «(/usr/bin/php -r \»chdir(‘ < $path_run >‘); < $str_requires >my_timeout_exec(\\\» < $my_target_exec >\\\», file_get_contents(‘php://stdin’), < $timeout >);\» my_timeout_exec ( $my_background_exec , json_encode ( $params ), 2 );
>

function my_timeout_exec ( $cmd , $stdin = » , $timeout )
< $start = time ();
$stdout = » ;
$stderr = » ;
//file_put_contents(‘debug.txt’, time().’:cmd:’.$cmd.»\n», FILE_APPEND);
//file_put_contents(‘debug.txt’, time().’:stdin:’.$stdin.»\n», FILE_APPEND);

$process = proc_open ( $cmd , [[ ‘pipe’ , ‘r’ ], [ ‘pipe’ , ‘w’ ], [ ‘pipe’ , ‘w’ ]], $pipes );
if (! is_resource ( $process ))
‘1’ , ‘stdout’ => $stdout , ‘stderr’ => $stderr );
>
$status = proc_get_status ( $process );
posix_setpgid ( $status [ ‘pid’ ], $status [ ‘pid’ ]); //seperate pgid(process group id) from parent’s pgid

Читайте также:  focus

stream_set_blocking ( $pipes [ 0 ], 0 );
stream_set_blocking ( $pipes [ 1 ], 0 );
stream_set_blocking ( $pipes [ 2 ], 0 );
fwrite ( $pipes [ 0 ], $stdin );
fclose ( $pipes [ 0 ]);

if ( time ()- $start > $timeout )
< //proc_terminate($process, 9); //only terminate subprocess, won't terminate sub-subprocess
posix_kill (- $status [ ‘pid’ ], 9 ); //sends SIGKILL to all processes inside group(negative means GPID, all subprocesses share the top process group, except nested my_timeout_exec)
//file_put_contents(‘debug.txt’, time().»:kill group \n», FILE_APPEND);
return array( ‘return’ => ‘1’ , ‘stdout’ => $stdout , ‘stderr’ => $stderr );
>

$status = proc_get_status ( $process );
//file_put_contents(‘debug.txt’, time().’:status:’.var_export($status, true).»\n»;
if (! $status [ ‘running’ ])
< fclose ( $pipes [ 1 ]);
fclose ( $pipes [ 2 ]);
proc_close ( $process );
return $status [ ‘exitcode’ ];
>

usleep ( 100000 );
>
>
?>

a_class.php:
class A
static function jack ( $a , $b )
< sleep ( 4 );
file_put_contents ( ‘debug.txt’ , time (). «:A::jack:» . $a . ‘ ‘ . $b . «\n» , FILE_APPEND );
sleep ( 15 );
>
>
?>

test.php:
require ‘my_exec.php’ ;

my_background_exec ( ‘A::jack’ , array( ‘hello’ , ‘jack’ ), ‘require «my_exec.php»;require «a_class.php»;’ , 8 );
?>

Источник

Проблемы «долгих» скриптов PHP

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

Внешний таймаут

В первую очередь нужно установить подходящее значение параметра max_execution_time в конфиге PHP.

Если скрипт запускается веб-сервером (т.е. в ответ на HTTP-запрос от пользователя), то следует также правильно настроить параметры таймаута в конфиге веб-сервера. Для apache это параметры TimeOut и FastCgiServer… -idle-timeout . (если PHP работает через FastCGI), для nginx send_timeout и fastcgi_read_timeout (если PHP работает через FastCGI).

Веб-сервер может также проксировать запросы на другой веб-сервер, который и запустит PHP скрипт (не редкий пример, nginx — фронтенд, apache — бэкэнд). В этом случае на проксирующем веб-сервере необходимо также настраивать таймаут проксирования. Для apache ProxyTimeout, для nginx proxy_read_timeout.

Прерывание пользователем

Если скрипт запускается в ответ на HTTP-запрос, то пользователь может остановить выполнение запроса в своем браузере, в этом случае прекратит свою работу и PHP скрипт. Если же требуется, чтобы скрипт продолжил свою работу даже после остановки запроса, установите в TRUE параметр ignore_user_abort в конфиге PHP.

Потеря открытых соединений

Если в скрипте открывается соединение с каким-либо сервисом/службой (с БД, с почтовым сервером, с FTP-сервером, . ), и во время выполнения скрипта некоторое время соединение не используется, то оно может быть закрыто этим сервисом. Например, если во время работы скрипта некоторое время не выполнять запросы к MySQL, то MySQL закроет соединение через время, заданное в параметре wait_timeout. Как следствие, при попытке выполнить очередной запрос возникнет ошибка.

Читайте также:  Основы разработки на php

В таких случаях следует в первую очередь попробовать увеличить таймаут соединения. Например, для MySQL можно выполнить запрос (спасибо Snowly)

SET SESSION wait_timeout = 9999 

Если же такой возможности нет или этот вариант по каким то причинам не подходит, то можно проверять активность соединения, в тех местах кода, где возможны простои его использования, и переподключаться при необходимости. Например в модуле MySQLi есть полезная функция mysqli::ping для проверки активности соединения, а также параметр конфигурации mysqli.reconnect для автоматического переподключения, при разрыве соединения. При отсутствии подобных функций для других видов соединений, можно попробовать написать ее самому. В ней нужно тривиальным образом обратиться к сервису и в случае ошибки (отловить при помощи try… catch . ) переподключиться. Например

class FtpConnection < private $ftp; public function connect() < $this->ftp = ftp_connect('ftp.server'); . > public function reconnect() < try < if (!ftp_pwd($this->ftp)) $this->connect(); > catch($e) < $this->connect(); > > . >
class MssqlConnection < private $db; public function connect() < $this->db = mssql_connect('mssql.server'); . > public function reconnect() < try < if (!mssql_query('SELECT 1 FROM dual', $this->db)) $this->connect(); > catch($e) < $this->connect(); > > . >

Параллельный запуск

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

В таких случаях можно использовать блокировку используемых ресурсов, но эта задача всегда решается индивидуально. Либо можно просто проверять, не запущена ли другая копия этого скрипта, и либо подождать завершения его работы, либо завершить текущий запуск. Для этого можно просматривать список запущенных процессов, либо использовать блокировку запуска самого скрипта, что то вроде:

Нагрузка на веб-сервер

В случаях, когда долгие скрипты запускаются через веб-сервер, соединение клиента с этим самым веб-сервером остается открытым до тех пор, пока не отработает скрипт. Это не есть хорошо, т.к. задача веб-сервера как можно быстрее обработать запрос и отдать результат. Если же соединение остается висеть, то один из воркеров (процессов) веб-сервера на долгое время будет занят. А если одновременно будет запущено достаточно много таких скриптов, то они могут занять все (ну или почти все) свободные воркеры (для apache см. MaxClients), и веб-сервер просто не сможет обрабатывать другие запросы.

Поэтому следует при обработке запроса пользователя, запускать скрипт в фоновом режиме через php-cli, чтобы не нагружать веб-сервер, а пользователю отвечать что его запрос обрабатывается. При необходимости можно периодически проверять состояние обработки при помощи AJAX запросов.

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

Источник

Оцените статью