PHP scripts that upload files, import data, or synchronize two databases often die halfway through for one reason: the default php.ini limits are tuned for serving page requests, not for batch work. When a script outlives a limit, PHP simply terminates it — your import stops at row 4,000 with no bug in your code to find.
The limits that matter
In php.ini, the resource section looks like this. Note that the CLI and web server usually read different ini files — check with php --ini on the command line versus phpinfo() through the web server.
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
max_execution_time = 240 ; per script, in seconds (0 = no limit)
max_input_time = 240 ; seconds spent parsing request data
memory_limit = 256M ; per-script memory ceiling
For forms that post large payloads and uploads, two more directives control the ceiling. Modern PHP still ships with surprisingly small defaults (post_max_size = 8M, upload_max_filesize = 2M), and post_max_size must always be larger than upload_max_filesize:
; Maximum size of POST data PHP will accept.
post_max_size = 30M
; Maximum allowed size for uploaded files.
upload_max_filesize = 25M
Raising limits without touching php.ini
On shared hosting you often cannot edit the main ini file, but you rarely need to. Most of these settings can be raised per-directory with a .user.ini file (CGI/FastCGI setups) or per-script at runtime:
Two caveats from running long jobs in production:
upload_max_filesizeandpost_max_sizeare "PHP_INI_PERDIR" — they cannot be changed withini_set()because PHP has already parsed the request by the time your script runs. Set them in.user.ini,.htaccess(php_value upload_max_filesize 25M) or the main ini.- On the CLI,
max_execution_timedoesn't count time spent in blocking calls likesleep(), stream reads or database queries — long-running imports there effectively run unbounded. - If nginx sits in front of PHP-FPM, raising
upload_max_filesizealone is not enough: also raiseclient_max_body_sizein the nginx config, or nginx will reject large uploads with a 413 before PHP ever sees them.
For genuinely long work — anything over a few minutes — resist the urge to raise limits ever higher. Push the job into a queue worker and let the web request return immediately. A script that needs ten minutes of execution time is an architecture smell, not a configuration problem.