false, 'message' => 'Only JPG, JPEG, PNG & GIF files are allowed.']; } // Check file size (5MB max) if ($file['size'] > 5 * 1024 * 1024) { return ['success' => false, 'message' => 'File size must be less than 5MB.']; } // Move uploaded file if (move_uploaded_file($file['tmp_name'], $target_file)) { // Resize image using GD resizeImage($target_file, 300, 300); return ['success' => true, 'filename' => $filename]; } return ['success' => false, 'message' => 'Failed to upload file.']; } function resizeImage($file_path, $max_width, $max_height) { if (!file_exists($file_path)) { return false; } list($width, $height, $type) = getimagesize($file_path); // Calculate new dimensions $ratio = min($max_width / $width, $max_height / $height); $new_width = $width * $ratio; $new_height = $height * $ratio; // Create new image $new_image = imagecreatetruecolor($new_width, $new_height); // Load image based on type switch ($type) { case IMAGETYPE_JPEG: $source = imagecreatefromjpeg($file_path); break; case IMAGETYPE_PNG: $source = imagecreatefrompng($file_path); // Preserve transparency imagealphablending($new_image, false); imagesavealpha($new_image, true); $transparent = imagecolorallocatealpha($new_image, 0, 0, 0, 127); imagefill($new_image, 0, 0, $transparent); break; case IMAGETYPE_GIF: $source = imagecreatefromgif($file_path); break; default: return false; } // Resize imagecopyresampled($new_image, $source, 0, 0, 0, 0, $new_width, $new_height, $width, $height); // Save based on type switch ($type) { case IMAGETYPE_JPEG: imagejpeg($new_image, $file_path, 90); break; case IMAGETYPE_PNG: imagepng($new_image, $file_path, 9); break; case IMAGETYPE_GIF: imagegif($new_image, $file_path); break; } // Free memory imagedestroy($source); imagedestroy($new_image); return true; } // FIXED: Improved QR Code generation with better error handling function generateQRCode($data, $unique_id) { $qr_dir = UPLOAD_PATH . 'qrcodes/'; if (!file_exists($qr_dir)) { mkdir($qr_dir, 0777, true); } $qr_file = $qr_dir . $unique_id . '.png'; // Prepare QR code data $qr_data = json_encode([ 'id' => $unique_id, 'name' => $data['full_name'], 'market' => $data['market_name'], 'shop' => $data['shop_no'], 'en_no' => $data['en_no'], 'whatsapp' => $data['whatsapp'] ?? '' ]); // Try multiple methods to get QR code // Method 1: Google Charts API $qr_url = 'https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl=' . urlencode($qr_data) . '&choe=UTF-8'; $qr_content = false; // Try file_get_contents if (ini_get('allow_url_fopen')) { $qr_content = @file_get_contents($qr_url); } // Try cURL if file_get_contents failed if ($qr_content === false && function_exists('curl_init')) { $ch = curl_init($qr_url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $qr_content = curl_exec($ch); curl_close($ch); } // If we got content and it's a valid PNG if ($qr_content !== false && !empty($qr_content)) { // Verify it's a PNG image $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_buffer($finfo, $qr_content); finfo_close($finfo); if (strpos($mime_type, 'image/png') !== false) { file_put_contents($qr_file, $qr_content); return 'qrcodes/' . $unique_id . '.png'; } } // Method 2: Create a simple QR-like image as fallback return createSimpleQRCode($qr_data, $qr_file, $unique_id); } // Create a simple QR-like image (fallback) function createSimpleQRCode($data, $file_path, $unique_id) { // Create a 300x300 image $img = imagecreate(300, 300); // Colors $white = imagecolorallocate($img, 255, 255, 255); $black = imagecolorallocate($img, 0, 0, 0); $green = imagecolorallocate($img, 0, 135, 81); // Fill background imagefill($img, 0, 0, $white); // Draw a stylized QR code pattern // Position markers (corners) imagefilledrectangle($img, 20, 20, 80, 80, $black); imagefilledrectangle($img, 25, 25, 75, 75, $white); imagefilledrectangle($img, 30, 30, 70, 70, $black); imagefilledrectangle($img, 220, 20, 280, 80, $black); imagefilledrectangle($img, 225, 25, 275, 75, $white); imagefilledrectangle($img, 230, 30, 270, 70, $black); imagefilledrectangle($img, 20, 220, 80, 280, $black); imagefilledrectangle($img, 25, 225, 75, 275, $white); imagefilledrectangle($img, 30, 230, 70, 270, $black); // Draw random data pattern for ($i = 0; $i < 20; $i++) { for ($j = 0; $j < 20; $j++) { if (($i + $j) % 3 == 0 || ($i * $j) % 5 == 0) { $x = 100 + $i * 8; $y = 100 + $j * 8; imagefilledrectangle($img, $x, $y, $x + 4, $y + 4, $black); } } } // Add ID text imagestring($img, 3, 90, 270, "ID: " . $unique_id, $green); // Save image imagepng($img, $file_path, 9); imagedestroy($img); return 'qrcodes/' . $unique_id . '.png'; } // FIXED: generateIDCard with proper error handling for images function generateIDCard($trader) { $card_dir = UPLOAD_PATH . 'id_cards/'; if (!file_exists($card_dir)) { mkdir($card_dir, 0777, true); } $output_file = $card_dir . $trader['unique_id'] . '.png'; // Create ID card using GD $width = 1012; $height = 638; // Create image $card = imagecreatetruecolor($width, $height); // Define colors $white = imagecolorallocate($card, 255, 255, 255); $green = imagecolorallocate($card, 0, 135, 81); $dark_green = imagecolorallocate($card, 0, 100, 60); $black = imagecolorallocate($card, 0, 0, 0); $gray = imagecolorallocate($card, 128, 128, 128); // Fill background imagefill($card, 0, 0, $white); // Add green header imagefilledrectangle($card, 0, 0, $width, 70, $green); // Add green footer imagefilledrectangle($card, 0, $height - 50, $width, $height, $green); // Add header text $header_text = "ANAMBRA STATE TRADERS ASSOCIATION"; $text_x = 200; $text_y = 25; for ($i = 0; $i < strlen($header_text); $i++) { imagestring($card, 5, $text_x + ($i * 12), $text_y, $header_text[$i], $white); } // Add photo with error handling $photo_path = UPLOAD_PATH . $trader['photo_path']; if (file_exists($photo_path)) { $photo_data = @file_get_contents($photo_path); if ($photo_data !== false) { $photo = @imagecreatefromstring($photo_data); if ($photo !== false) { $photo = resizeImageGDSafe($photo, 150, 150); if ($photo !== false) { imagecopy($card, $photo, 30, 90, 0, 0, 150, 150); imagedestroy($photo); // Add border around photo imagerectangle($card, 29, 89, 181, 241, $green); } } } } // Add trader details $details_x = 200; $details_y = 90; $line_height = 28; // Function to write text with label function writeDetail($card, $label, $value, $x, &$y, $line_height, $black) { imagestring($card, 4, $x, $y, $label, $black); imagestring($card, 4, $x + 80, $y, $value, $black); $y += $line_height; } writeDetail($card, "Name:", substr($trader['full_name'], 0, 30), $details_x, $details_y, $line_height, $black); writeDetail($card, "Market:", substr($trader['market_name'], 0, 25), $details_x, $details_y, $line_height, $black); writeDetail($card, "LGA:", $trader['market_lga'], $details_x, $details_y, $line_height, $black); writeDetail($card, "EN No:", $trader['en_no'], $details_x, $details_y, $line_height, $black); writeDetail($card, "Shop No:", $trader['shop_no'], $details_x, $details_y, $line_height, $black); writeDetail($card, "ID No:", $trader['unique_id'], $details_x, $details_y, $line_height, $black); // Add QR code with error handling $qr_path = UPLOAD_PATH . $trader['qr_code_path']; if (file_exists($qr_path)) { $qr_data = @file_get_contents($qr_path); if ($qr_data !== false) { $qr = @imagecreatefromstring($qr_data); if ($qr !== false) { $qr = resizeImageGDSafe($qr, 120, 120); if ($qr !== false) { imagecopy($card, $qr, $width - 150, $height - 170, 0, 0, 120, 120); imagedestroy($qr); // Add border around QR imagerectangle($card, $width - 151, $height - 171, $width - 29, $height - 49, $white); } } } } // If QR code couldn't be loaded, add text placeholder if (!isset($qr) || $qr === false) { imagestring($card, 3, $width - 150, $height - 130, "QR Code", $black); imagestring($card, 2, $width - 160, $height - 110, $trader['unique_id'], $black); } // Add date $date_text = "Issue Date: " . date('d/m/Y', strtotime($trader['created_at'])); imagestring($card, 3, $width - 250, $height - 30, $date_text, $white); // Save the ID card imagepng($card, $output_file, 9); imagedestroy($card); return 'id_cards/' . $trader['unique_id'] . '.png'; } // Safe image resizing function with error handling function resizeImageGDSafe($image, $new_width, $new_height) { if ($image === false) { return false; } $width = imagesx($image); $height = imagesy($image); if ($width === false || $height === false) { return false; } $new_image = imagecreatetruecolor($new_width, $new_height); // Preserve transparency for PNG imagealphablending($new_image, false); imagesavealpha($new_image, true); $transparent = imagecolorallocatealpha($new_image, 0, 0, 0, 127); imagefill($new_image, 0, 0, $transparent); $result = imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height); if ($result === false) { imagedestroy($new_image); return false; } return $new_image; } // Generate ID card PDF function generateIDCardPDF($trader) { // Check if FPDF exists $fpdf_path = __DIR__ . '/../vendor/fpdf/fpdf.php'; if (file_exists($fpdf_path)) { require_once $fpdf_path; class PDF extends FPDF { function Header() {} function Footer() {} } $pdf = new PDF('L', 'mm', array(86, 54)); $pdf->AddPage(); // Set colors $pdf->SetFillColor(0, 135, 81); $pdf->SetTextColor(255, 255, 255); // Header $pdf->Rect(0, 0, 86, 8, 'F'); $pdf->SetFont('Arial', 'B', 8); $pdf->SetXY(0, 1); $pdf->Cell(86, 6, 'ANAMBRA STATE TRADERS ASSOCIATION', 0, 1, 'C'); // Reset text color for details $pdf->SetTextColor(0, 0, 0); // Photo $photo_path = UPLOAD_PATH . $trader['photo_path']; if (file_exists($photo_path)) { $pdf->Image($photo_path, 5, 12, 15, 15); } // Details $pdf->SetFont('Arial', 'B', 7); $pdf->SetXY(22, 12); $pdf->Cell(15, 4, 'Name:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, substr($trader['full_name'], 0, 25), 0, 1); $pdf->SetFont('Arial', 'B', 7); $pdf->SetX(22); $pdf->Cell(15, 4, 'Market:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, substr($trader['market_name'], 0, 20), 0, 1); $pdf->SetFont('Arial', 'B', 7); $pdf->SetX(22); $pdf->Cell(15, 4, 'LGA:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, $trader['market_lga'], 0, 1); $pdf->SetFont('Arial', 'B', 7); $pdf->SetX(22); $pdf->Cell(15, 4, 'EN No:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, $trader['en_no'], 0, 1); $pdf->SetFont('Arial', 'B', 7); $pdf->SetX(22); $pdf->Cell(15, 4, 'Shop No:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, $trader['shop_no'], 0, 1); $pdf->SetFont('Arial', 'B', 7); $pdf->SetX(22); $pdf->Cell(15, 4, 'ID No:', 0, 0); $pdf->SetFont('Arial', '', 7); $pdf->Cell(40, 4, $trader['unique_id'], 0, 1); // QR Code $qr_path = UPLOAD_PATH . $trader['qr_code_path']; if (file_exists($qr_path)) { $pdf->Image($qr_path, 65, 30, 15, 15); } // Footer with date $pdf->SetY(48); $pdf->SetFont('Arial', 'I', 5); $pdf->SetTextColor(255, 255, 255); $pdf->Cell(86, 4, 'Issue Date: ' . date('d/m/Y', strtotime($trader['created_at'])), 0, 1, 'C'); return $pdf; } return null; } function getMarkets() { global $conn; $query = "SELECT * FROM markets ORDER BY market_name"; $result = $conn->query($query); $markets = []; while ($row = $result->fetch_assoc()) { $markets[] = $row; } return $markets; } function getTraders($page = 1, $per_page = 10, $market_filter = '') { global $conn; $offset = ($page - 1) * $per_page; $where = ''; if (!empty($market_filter)) { $where = "WHERE market_name = '" . $conn->real_escape_string($market_filter) . "'"; } $query = "SELECT * FROM traders $where ORDER BY created_at DESC LIMIT $offset, $per_page"; $result = $conn->query($query); $count_query = "SELECT COUNT(*) as total FROM traders $where"; $count_result = $conn->query($count_query); $total = $count_result->fetch_assoc()['total']; $traders = []; while ($row = $result->fetch_assoc()) { $traders[] = $row; } return [ 'traders' => $traders, 'total' => $total, 'pages' => ceil($total / $per_page), 'current_page' => $page ]; } function getStates() { return [ 'Abia', 'Adamawa', 'Akwa Ibom', 'Anambra', 'Bauchi', 'Bayelsa', 'Benue', 'Borno', 'Cross River', 'Delta', 'Ebonyi', 'Edo', 'Ekiti', 'Enugu', 'FCT - Abuja', 'Gombe', 'Imo', 'Jigawa', 'Kaduna', 'Kano', 'Katsina', 'Kebbi', 'Kogi', 'Kwara', 'Lagos', 'Nasarawa', 'Niger', 'Ogun', 'Ondo', 'Osun', 'Oyo', 'Plateau', 'Rivers', 'Sokoto', 'Taraba', 'Yobe', 'Zamfara' ]; } function getLGA($state) { $lgas = [ 'Anambra' => [ 'Aguata', 'Anambra East', 'Anambra West', 'Anaocha', 'Awka North', 'Awka South', 'Ayamelum', 'Dunukofia', 'Ekwusigo', 'Idemili North', 'Idemili South', 'Ihiala', 'Njikoka', 'Nnewi North', 'Nnewi South', 'Ogbaru', 'Onitsha North', 'Onitsha South', 'Orumba North', 'Orumba South', 'Oyi' ] ]; return isset($lgas[$state]) ? $lgas[$state] : []; } ?>