0) ob_end_clean(); http_response_code(400); header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Parameter group_name is required']); exit; } try { $db = db(); // 1. Fetch group by name $stmt = $db->prepare('SELECT id, name FROM bni_groups WHERE LOWER(name) = LOWER(?)'); $stmt->execute([trim($group_name)]); $group = $stmt->fetch(PDO::FETCH_ASSOC); if (!$group) { while (ob_get_level() > 0) ob_end_clean(); http_response_code(404); header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Group not found']); exit; } $groupId = $group['id']; $groupRealName = $group['name']; // 2. Fetch members $stmt = $db->prepare(' SELECT p.first_name, p.last_name, p.person_photo_path, p.company_name, p.company_logo_path, p.business_description, p.industry, p.company_size FROM people p WHERE p.bni_group_id = ? ORDER BY p.last_name ASC, p.first_name ASC '); $stmt->execute([$groupId]); $members = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($members)) { while (ob_get_level() > 0) ob_end_clean(); http_response_code(404); header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'No members found in this group']); exit; } // Helper to validate images before adding to PDF $tempFiles = []; function getVerifiedImagePath($path, &$tempFiles) { if (empty($path)) return null; // Local file if (strpos($path, 'http') !== 0) { $localPath = rtrim(realpath(__DIR__), '/') . '/' . ltrim($path, '/'); if (!file_exists($localPath)) return null; $info = @getimagesize($localPath); if ($info && in_array($info[2], [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG])) { return $localPath; } return null; } // URL $ch = curl_init($path); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, 3); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $data = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($code >= 200 && $code < 300 && $data) { $tmp = tempnam(sys_get_temp_dir(), 'pdfimg_'); file_put_contents($tmp, $data); $info = @getimagesize($tmp); if ($info && in_array($info[2], [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG])) { $tempFiles[] = $tmp; return $tmp; } @unlink($tmp); } return null; } // 3. Create PDF $pdf = new tFPDF(); $pdf->AddFont('DejaVu', '', 'DejaVuSans.ttf', true); $pdf->AddFont('DejaVu', 'B', 'DejaVuSans-Bold.ttf', true); $pdf->SetMargins(15, 20, 15); $pdf->SetAutoPageBreak(true, 15); foreach ($members as $member) { $pdf->AddPage(); // --- HEADER --- $pdf->SetFont('DejaVu', 'B', 12); $pdf->SetTextColor(150, 150, 150); $pdf->Cell(0, 10, 'Grupa: ' . $groupRealName, 0, 1, 'R'); $pdf->Ln(5); $pdf->SetTextColor(0, 0, 0); // --- IMAGES --- $yStart = $pdf->GetY(); $minY = $yStart; // Left - Photo if (!empty($member['person_photo_path'])) { $validPath = getVerifiedImagePath($member['person_photo_path'], $tempFiles); if ($validPath) { @$pdf->Image($validPath, 15, $yStart, 40); $minY = max($minY, $yStart + 50); } } // Right - Logo if (!empty($member['company_logo_path'])) { $validPath = getVerifiedImagePath($member['company_logo_path'], $tempFiles); if ($validPath) { @$pdf->Image($validPath, 155, $yStart, 40); $minY = max($minY, $yStart + 50); } } // --- MAIN INFO --- $pdf->SetY($yStart + 10); $name = trim($member['first_name'] . ' ' . $member['last_name']); if ($name === '') { $name = 'Nieznany członek'; } $pdf->SetFont('DejaVu', 'B', 22); // Add margins for text so it doesn't overlap images $pdf->SetLeftMargin(55); $pdf->SetRightMargin(55); $pdf->Cell(100, 12, $name, 0, 1, 'C'); $companyName = trim($member['company_name'] ?? ''); if ($companyName !== '') { $pdf->SetFont('DejaVu', 'B', 16); $pdf->SetTextColor(80, 80, 80); $pdf->MultiCell(100, 8, $companyName, 0, 'C'); $pdf->SetTextColor(0, 0, 0); } // Reset margins $pdf->SetLeftMargin(15); $pdf->SetRightMargin(15); $pdf->SetX(15); // Ensure we draw details below the images if ($pdf->GetY() < $minY) { $pdf->SetY($minY + 5); } else { $pdf->Ln(10); } // --- DETAILS --- $pdf->SetFont('DejaVu', 'B', 12); // Industry $pdf->Cell(45, 8, 'Branża:', 0, 0); $pdf->SetFont('DejaVu', '', 12); $industry = trim($member['industry'] ?? ''); $pdf->Cell(0, 8, $industry !== '' ? $industry : '-', 0, 1); // Company Size $pdf->SetFont('DejaVu', 'B', 12); $pdf->Cell(45, 8, 'Wielkość firmy:', 0, 0); $pdf->SetFont('DejaVu', '', 12); $companySize = trim($member['company_size'] ?? ''); $pdf->Cell(0, 8, $companySize !== '' ? $companySize : '-', 0, 1); $pdf->Ln(8); // Description $pdf->SetFont('DejaVu', 'B', 12); $pdf->Cell(0, 8, 'Opis:', 0, 1); $pdf->SetFont('DejaVu', '', 11); $desc = trim($member['business_description'] ?? ''); if ($desc === '') { $desc = 'Brak opisu.'; } $pdf->MultiCell(0, 6, $desc); } // Clear buffer before sending headers while (ob_get_level() > 0) ob_end_clean(); $safeName = preg_replace('/[^a-zA-Z0-9_\-]/', '_', strtolower($groupRealName)); $filename = 'lista_czlonkow_' . $safeName . '.pdf'; header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Cache-Control: private, max-age=0, must-revalidate'); header('Pragma: public'); // Output directly $pdf->Output('D', $filename); // Cleanup foreach ($tempFiles as $tmp) { @unlink($tmp); } exit; } catch (Exception $e) { while (ob_get_level() > 0) ob_end_clean(); http_response_code(500); header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Wystąpił błąd podczas generowania PDF', 'details' => $e->getMessage()]); exit; }