Skip to content

pr: [Nightly Fix] - Null Safety - Guard Empty Imports#4

Open
jewel-claw wants to merge 1 commit intomasterfrom
nightly-fix/empty-import-guard
Open

pr: [Nightly Fix] - Null Safety - Guard Empty Imports#4
jewel-claw wants to merge 1 commit intomasterfrom
nightly-fix/empty-import-guard

Conversation

@jewel-claw
Copy link

What

  • reject empty import payloads before creating a table or dereferencing the first row

Why

  • empty CSV and drag-and-drop imports can currently flow through to code paths that assume at least one row exists
  • that can lead to undefined offset access and blank table records being created from invalid input

Fix

  • add explicit empty-file and missing-header checks in the CSV importer
  • add an early guard in the drag-and-drop/import-from-URL path when no rows were parsed

Confidence

  • linted app/Http/Controllers/ImportController.php with php -l

@greptile-apps
Copy link

greptile-apps bot commented Mar 10, 2026

PR author is not in the allowed authors list.

@qodo-code-review
Copy link

Review Summary by Qodo

Guard against empty imports and missing headers

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add empty file validation in CSV importer before processing
• Add missing header row validation in CSV importer
• Add empty data guard in drag-and-drop import path
• Prevent undefined offset access and invalid table creation
Diagram
flowchart LR
  CSV["CSV Upload"] --> Parse["Parse CSV"]
  Parse --> CheckEmpty["Check if empty"]
  CheckEmpty -->|Empty| Error1["Return error: empty file"]
  CheckEmpty -->|Not empty| ExtractHeader["Extract header"]
  ExtractHeader --> CheckHeader["Check header exists"]
  CheckHeader -->|Missing| Error2["Return error: missing header"]
  CheckHeader -->|Valid| CreateTable["Create table"]
  
  DragDrop["Drag & Drop/URL Import"] --> GetData["Get data"]
  GetData --> Sanitize["Sanitize data"]
  Sanitize --> CheckRows["Check if has rows"]
  CheckRows -->|Empty| Error3["Return error: no rows"]
  CheckRows -->|Has rows| SaveTable["Save table"]
Loading

Grey Divider

File Changes

1. app/Http/Controllers/ImportController.php 🐞 Bug fix +25/-0

Add null safety guards for empty imports

• Added empty file validation after CSV parsing to reject empty imports
• Added missing header row validation to ensure header exists and is array
• Added empty data guard in extracted method for drag-and-drop/URL imports
• All validations return appropriate error messages with 423 status code

app/Http/Controllers/ImportController.php


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 10, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. CSV error response dropped 🐞 Bug ✓ Correctness
Description
defaultImport() calls uploadTableCsv() without returning its WP_REST_Response, so the new
sendError() returns for empty/header-missing CSVs are discarded and the handler continues to the
generic “No appropriate driver found” response. This prevents the intended validation message from
reaching clients and makes the new guards ineffective for user feedback.
Code

app/Http/Controllers/ImportController.php[R106-113]

+        if (empty($reader)) {
+            return $this->sendError([
+                'data' => [
+                    'errors'  => array(),
+                    'message' => __('The imported CSV file is empty.', 'ninja-tables')
+                ]
+            ], 423);
+        }
Evidence
uploadTableCsv() now returns a WP_REST_Response via sendError() on validation failures (including
the newly added empty CSV guard). In the REST route handler defaultImport(), the call result is not
returned; execution continues and a different JSON response is sent, masking the original error
response object (sendError does not terminate execution).

app/Http/Controllers/ImportController.php[28-58]
app/Http/Controllers/ImportController.php[106-113]
vendor/wpfluent/framework/src/WPFluent/Http/Controller.php[127-141]
vendor/wpfluent/framework/src/WPFluent/Http/Response/Response.php[116-123]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`defaultImport()` calls the specific importer methods but does **not** `return` their responses. When `uploadTableCsv()` returns via `sendError()` (including the new empty/header checks), the response object is discarded and `defaultImport()` continues to send the generic fallback error.

### Issue Context
`sendError()` returns a `WP_REST_Response` and does not terminate execution. The REST router expects the controller method to return that response.

### Fix Focus Areas
- app/Http/Controllers/ImportController.php[28-58]
- app/Http/Controllers/ImportController.php[106-124]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Blank header row allowed 🐞 Bug ✓ Correctness
Description
uploadTableCsv()’s new header guard only checks that the shifted header is a non-empty array, so a
header like ",,," passes and stores empty column names. This results in blank column labels in admin
UI (e.g., sorting dropdown) and generates malformed sample CSV headers.
Code

app/Http/Controllers/ImportController.php[R115-124]

        $header = array_shift($reader);

+        if (empty($header) || !is_array($header)) {
+            return $this->sendError([
+                'data' => [
+                    'errors'  => array(),
+                    'message' => __('The imported CSV file is missing a header row.', 'ninja-tables')
+                ]
+            ], 423);
+        }
Evidence
The new validation does not verify that any header cell contains a non-empty name, and the system
persists raw header values as column names. Multiple UI locations display column.name directly;
with empty names this produces blank option labels and empty CSV headers.

app/Http/Controllers/ImportController.php[115-124]
boot/ninja-tables-global-function.php[505-527]
app/Http/Controllers/ImportController.php[162-173]
resources/admin/components/Table/TableDesignStudio.vue[660-666]
resources/admin/components/Table/Tools/Import.vue[180-184]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The new header guard only validates that `$header` is a non-empty array; it does not validate that header cell values are non-empty. CSV inputs like `",,,"` pass and create columns with empty display names.

### Issue Context
Column names are persisted from the header values and are displayed directly in parts of the UI; empty names produce blank labels and malformed CSV header output.

### Fix Focus Areas
- app/Http/Controllers/ImportController.php[115-124]
- boot/ninja-tables-global-function.php[505-527]
- app/Http/Controllers/ImportController.php[162-173]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@kilo-code-bot
Copy link

kilo-code-bot bot commented Mar 10, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
app/Http/Controllers/ImportController.php 107-112, 118-123 Inconsistent error response structure - wraps in 'data' => [...] but line 448 does not
Other Observations (not in diff)

No issues found in unchanged code.

Files Reviewed (1 file)
  • app/Http/Controllers/ImportController.php - 1 issue

Code Quality Assessment

Positive changes:

  • ✅ Added empty file validation for CSV imports (prevents undefined behavior)
  • ✅ Added missing header row validation (prevents invalid table creation)
  • ✅ Added empty data guard for drag-and-drop/URL imports
  • ✅ All validations return appropriate error messages with 423 status code

Issue details:

The new error responses at lines 107-112 and 118-123 wrap the error in a 'data' => [...] key, but the error at line 448 (for empty data in extracted method) uses the format ['errors' => [], 'message' => ...] without the 'data' wrapper. This is inconsistent with:

  1. The new error at line 448
  2. Existing error at lines 36-40 which also uses ['errors' => [], 'message' => ...]

Recommendation: Make the error response structure consistent across all validation checks - either all should have 'data' wrapper or none should.


Review generated by Kilo Code Review

Comment on lines +106 to +113
if (empty($reader)) {
return $this->sendError([
'data' => [
'errors' => array(),
'message' => __('The imported CSV file is empty.', 'ninja-tables')
]
], 423);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Csv error response dropped 🐞 Bug ✓ Correctness

defaultImport() calls uploadTableCsv() without returning its WP_REST_Response, so the new
sendError() returns for empty/header-missing CSVs are discarded and the handler continues to the
generic “No appropriate driver found” response. This prevents the intended validation message from
reaching clients and makes the new guards ineffective for user feedback.
Agent Prompt
### Issue description
`defaultImport()` calls the specific importer methods but does **not** `return` their responses. When `uploadTableCsv()` returns via `sendError()` (including the new empty/header checks), the response object is discarded and `defaultImport()` continues to send the generic fallback error.

### Issue Context
`sendError()` returns a `WP_REST_Response` and does not terminate execution. The REST router expects the controller method to return that response.

### Fix Focus Areas
- app/Http/Controllers/ImportController.php[28-58]
- app/Http/Controllers/ImportController.php[106-124]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant