>|WP_Error|null $rows Raw export rows, or * the database error when the query failed. * @return WP_Error|null The original failure, or null on success. */ public static function write(string $tempFile, $rows): ?WP_Error { if (file_exists($tempFile)) { ABJ_404_Solution_FileSystemService::safeUnlink($tempFile); } if ($rows instanceof WP_Error) { return $rows; } if ($rows === null) { return null; } $fh = fopen($tempFile, 'w'); if ($fh === false) { return null; } // try/finally: a row source that throws mid-stream (mysqli's default // error mode, MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT since PHP 8.1, // throws mysqli_sql_exception on a dropped connection mid-fetch) must // not skip fclose($fh) and leak the file handle. Same resource-lifecycle // shape as includes/import/ImportService.php::doImportFile(). try { fputcsv($fh, self::HEADER, ',', '"', '\\'); foreach ($rows as $row) { fputcsv($fh, ABJ_404_Solution_RedirectExportDestination::csvColumns($row), ',', '"', '\\'); } } finally { fclose($fh); } return null; } }