Question

PHP Maximum Execution Time Exceeded: Diagnose and Fix Long-Running Scripts

phpjson

Question

I am downloading a JSON file from an online source. When my PHP script processes the data in a loop, it produces this error:

Fatal error: Maximum execution time of 30 seconds exceeded in C:\wamp\www\temp\fetch.php on line 24

What does this error mean, and how can I identify and fix the part of the download or loop that is taking too long?

Short Answer

You will learn how PHP execution time limits work, why a long-running loop or network request can exceed them, and how to diagnose the real bottleneck. You will also see safer solutions such as validating input, setting network timeouts, processing data in batches, and using pagination instead of only increasing the limit.

Concept

PHP applies a maximum execution time to prevent one request from running forever and consuming server resources. In many local PHP installations, the default value is 30 seconds.

When PHP reaches that limit, it stops the script and reports the file and line that was executing when time expired. The reported line is not always the original cause. For example, a slow HTTP download, an infinite loop, or expensive work inside an earlier loop iteration can make PHP eventually stop at line 24.

Common causes include:

  • A loop that never reaches its stopping condition.
  • A very large JSON response that takes a long time to download or decode.
  • Repeated HTTP requests inside a loop.
  • Slow database, file-system, or API operations inside a loop.
  • Processing every record at once when the API supports pages or smaller batches.

Increasing the time limit can be appropriate for a known, intentional background task. However, it should not be the first fix: an accidental infinite loop will still run forever, only for longer.

Mental Model

Think of the PHP time limit as a timer on an exam.

  • Your script is the student doing work.
  • Each loop iteration is another question.
  • Downloading data is waiting for a document to arrive.
  • The execution limit is the exam bell.

If the document never arrives, or the student keeps answering the same question without moving forward, the bell rings. Giving the student more time helps only when there is genuinely more valid work to complete. It does not fix a student who is stuck on the same question.

Take Quiz

Syntax and Examples

The configured limit is commonly set in php.ini:

max_execution_time = 30

For a specific script, PHP can request a different limit with set_time_limit():

<?php
set_time_limit(60); // Allow up to 60 seconds for this script.

for ($i = 1; $i <= 5; $i++) {
    echo "Processing item {$i}\n";
}

You can inspect the configured value:

<?php
$limit = ini_get('max_execution_time');
echo "Maximum execution time: {$limit} seconds";

For remote JSON, set a network timeout as well. set_time_limit() controls PHP's script limit; a stream context controls how long an HTTP request may wait.

<?php
$url = 'https://example.com/data.json';

$context = stream_context_create([
    'http' => [
        'timeout' => 10,
    ],
]);

$json = file_get_contents($url, false, $context);

if ($json === false) {
    throw new RuntimeException('The JSON file could not be downloaded.');
}

$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

foreach ($data as $item) {
    // Process one item.
}

This example fails clearly after a slow request instead of waiting indefinitely. JSON_THROW_ON_ERROR also makes invalid JSON visible as an exception rather than silently returning null.

Step by Step Execution

Consider this traceable example:

<?php
$items = [10, 20, 30];
$total = 0;

foreach ($items as $item) {
    $total += $item;
}

echo $total;

Execution proceeds as follows:

  1. $items is created with three values.
  2. $total starts at 0.
  3. First iteration: $item is 10; $total becomes 10.
  4. Second iteration: $item is 20; $total becomes 30.
  5. Third iteration: $item is 30; $total becomes 60.
  6. The array has no more values, so foreach ends.
  7. The script prints 60.

Now compare it with a faulty while loop:

<?php
$count = 0;

while ($count < 3) {
    echo $count;
    // $count is never increased.
}

$count remains 0, so 0 < 3 is always true. The loop never ends and eventually reaches PHP's execution time limit. The correction is to update the value that controls the condition:

<?php
$count = 0;

while ($count < 3) {
    echo $count;
    $count++;
}

Real World Use Cases

Execution-time awareness matters whenever a request performs more than a small, immediate action:

  • API imports: Download product, weather, or customer JSON from an external API.
  • Data synchronization: Update local records from a remote service in batches.
  • Report generation: Aggregate many rows before exporting CSV or PDF data.
  • Image or file processing: Resize many uploads without blocking a web request too long.
  • Admin tools: Import a spreadsheet while reporting errors for invalid rows.

For browser-triggered work, keep requests short where possible. Large imports are often better handled as scheduled command-line jobs or queue workers, where progress, retries, and logging are easier to manage.

Take Quiz

Real Codebase Usage

In production code, developers usually address the source of slowness rather than placing one large timeout around everything.

Use guard clauses for failed downloads

<?php
$json = file_get_contents($url, false, $context);

if ($json === false) {
    throw new RuntimeException('Remote API request failed.');
}

This prevents later code from trying to decode or loop over a failed response.

Validate JSON before processing

<?php
$data = json_decode($json, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    throw new RuntimeException('Invalid JSON: ' . json_last_error_msg());
}

if (!is_array($data)) {
    throw new UnexpectedValueException('Expected the JSON root to be an array.');
}

Process predictable batches

<?php
foreach (array_chunk($data, 100) as $batch) {
    foreach ($batch as $item) {
        // Save or transform one item.
    }
}

Batching makes work easier to measure and can allow database writes to happen in manageable groups.

Prefer API pagination

If an API provides page, limit, or cursor parameters, request a limited number of records at a time rather than downloading an entire dataset in one response.

Measure slow sections

<?php
$startedAt = microtime(true);

// Download or process data here.

$seconds = microtime(true) - $startedAt;
error_log("Import completed in {$seconds} seconds");

Time the download, JSON decoding, and loop separately. This tells you whether the bottleneck is the network, parsing, database writes, or loop logic.

Common Mistakes

Only increasing the execution limit

<?php
set_time_limit(600);

while (true) {
    // Still never ends.
}

A larger limit hides the symptom temporarily but does not repair an infinite loop. First verify that every loop has a reachable stopping condition.

Forgetting to update a loop counter

<?php
$page = 1;

while ($page <= 10) {
    // Fetch page data.
    // Missing: $page++
}

Update the counter, or break when the API says there are no more results.

Making an HTTP request for every item

<?php
foreach ($ids as $id) {
    $json = file_get_contents("https://api.example.com/items/{$id}");
}

Hundreds of sequential remote requests can easily exceed a request budget. Use a bulk endpoint, pagination, caching, or background processing when available.

Ignoring download failure

<?php
$data = json_decode(file_get_contents($url), true);
foreach ($data as $item) {
    // May warn or fail if the download returned false.
}

Check that the download succeeded and that the decoded JSON has the expected structure before looping.

Assuming the error line is the exact cause

The line in the error is where PHP was when the timer expired. Add timing logs around downloads and expensive operations to find what consumed the time.

Changing php.ini but not restarting the server

When changing max_execution_time in php.ini, restart Apache, PHP-FPM, or the relevant local server process. Verify the active value with ini_get() or phpinfo().

Comparisons

ApproachWhat it solvesBest useLimitation
Fix loop conditionInfinite or runaway loopsA counter, cursor, or condition does not advanceDoes not make a genuinely slow API faster
set_time_limit(60)A legitimate job that needs slightly longerControlled scripts with known workDoes not fix bad logic; server policy may restrict it
HTTP client timeoutA remote server that responds too slowlyDownloads and API callsDoes not reduce local processing time
BatchingLarge local processing workloadsImports and database writesRequires code to track batches/progress
PaginationOversized API responsesAPIs that expose pages or cursorsRequires API support
Background worker or CLI jobWork too large for a web requestImports, reports, media processingRequires job scheduling or queue infrastructure

max_execution_time is a PHP runtime limit. A network timeout is a request-level limit. Use both when downloading remote data, because they protect against different failures.

Take Quiz

Cheat Sheet

// Read the configured script time limit.
echo ini_get('max_execution_time');

// Request a limit for the current script.
set_time_limit(60);

// Stop waiting on an HTTP stream after 10 seconds.
$context = stream_context_create([
    'http' => ['timeout' => 10],
]);

$json = file_get_contents($url, false, $context);
if ($json === false) {
    throw new RuntimeException('Download failed');
}

// Decode JSON and throw on malformed content.
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
  • The default execution limit is often 30 seconds, but check your active configuration.
  • The error line is where execution stopped, not necessarily where the slowdown began.
  • Ensure every while loop changes data used by its condition.
  • Set a network timeout for remote requests.
  • Validate a download and decoded JSON before iterating.
  • Use batches or API pages for large datasets.
  • Increase the execution limit only after confirming the work is valid and finite.

FAQ

What does “Maximum execution time of 30 seconds exceeded” mean in PHP?

PHP stopped the script because it ran longer than its configured execution-time limit, commonly 30 seconds.

Does the reported line contain the bug?

Not always. It is the line PHP was executing when the timer expired. The actual delay may be an earlier network request or expensive work repeated in a loop.

How do I increase the PHP execution time limit?

Use set_time_limit(60) for the current script, or change max_execution_time in the active php.ini and restart the server. Fix the cause first.

Why does increasing max_execution_time not fix my script?

It only allows more time. An infinite loop, unavailable API, or unbounded import can still run until the new limit is reached.

How can I prevent a slow JSON download from blocking PHP?

Set an HTTP timeout using a stream context or an HTTP client, check for request failure, and handle the error before decoding JSON.

Should I download all API data in one request?

Usually not when the API supports pagination. Request smaller pages, process each page, and stop when there are no more results.

Is this a memory-limit error?

No. Execution time and memory are separate limits. A memory error typically mentions Allowed memory size exhausted.

Take Quiz

Mini Project

Description

Build a small PHP JSON importer that downloads a remote list, validates it, processes records in batches, and reports how long the work took. This mirrors a basic data-import endpoint while keeping network and processing failures visible.

Goal

Safely fetch JSON and process each valid record without relying on an unbounded loop or a single silent failure.

Requirements

Use an HTTP timeout when downloading the JSON.|Stop with a clear error if the download or JSON decoding fails.|Confirm that the decoded JSON is an array before processing it.|Process the records in batches of 100.|Print the number of processed records and elapsed time.

Take Quiz

Keep learning

Related questions

View more