303 lines
8.3 KiB
PHP
303 lines
8.3 KiB
PHP
<?php
|
||
/**
|
||
* MSIN-4485 — Impression dossard PDF (1 participant).
|
||
*
|
||
* Format FINAL : demi-feuille Lettre coupée sur le 11"
|
||
* → papier 8.5" large × 5.5" haut (paysage)
|
||
* → PDF page = exactement cette taille
|
||
* → fond pleine page + n° / nom / QR alignés
|
||
*
|
||
* Impression : papier personnalisé 8.5 × 5.5, échelle 100 %, sans « ajuster à la page ».
|
||
*/
|
||
|
||
define('MSIN_DOSSARD_PRINT_PERM', 'inscriptions_gestion.dossard_print');
|
||
|
||
/**
|
||
* Taille page = feuille coupée (pouces → mm).
|
||
* Lettre 8.5×11 coupée en 2 sur le 11" → 8.5 × 5.5.
|
||
*
|
||
* @return array{0:float,1:float} [largeur, hauteur]
|
||
*/
|
||
function fxDossardPrintPageSizeMm()
|
||
{
|
||
return array(8.5 * 25.4, 5.5 * 25.4);
|
||
}
|
||
|
||
/** Dossier des fonds JPG/PNG (même ratio 8.5:5.5 recommandé). */
|
||
function fxDossardPrintTemplatesDir()
|
||
{
|
||
return dirname(__DIR__) . '/assets/dossard_templates';
|
||
}
|
||
|
||
/**
|
||
* Fond : eve_{id}.jpg|png sinon default.jpg|png.
|
||
*
|
||
* @return string|null
|
||
*/
|
||
function fxDossardPrintResolveTemplatePath($intEveId)
|
||
{
|
||
$strDir = fxDossardPrintTemplatesDir();
|
||
$intEveId = intval($intEveId);
|
||
$arrCandidates = array();
|
||
if ($intEveId > 0) {
|
||
$arrCandidates[] = $strDir . '/eve_' . $intEveId . '.jpg';
|
||
$arrCandidates[] = $strDir . '/eve_' . $intEveId . '.jpeg';
|
||
$arrCandidates[] = $strDir . '/eve_' . $intEveId . '.png';
|
||
}
|
||
$arrCandidates[] = $strDir . '/default.jpg';
|
||
$arrCandidates[] = $strDir . '/default.jpeg';
|
||
$arrCandidates[] = $strDir . '/default.png';
|
||
|
||
foreach ($arrCandidates as $strPath) {
|
||
if (is_file($strPath)) {
|
||
return $strPath;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Type FPDF d'après le fichier réel.
|
||
*
|
||
* @return string JPG|PNG|GIF|''
|
||
*/
|
||
function fxDossardPrintImageType($strPath)
|
||
{
|
||
$arrInfo = @getimagesize($strPath);
|
||
if (!is_array($arrInfo) || empty($arrInfo[2])) {
|
||
return '';
|
||
}
|
||
if ((int)$arrInfo[2] === IMAGETYPE_JPEG) {
|
||
return 'JPG';
|
||
}
|
||
if ((int)$arrInfo[2] === IMAGETYPE_PNG) {
|
||
return 'PNG';
|
||
}
|
||
if ((int)$arrInfo[2] === IMAGETYPE_GIF) {
|
||
return 'GIF';
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
/** Texte FPDF (core fonts = Windows-1252). */
|
||
function fxDossardPrintPdfText($str)
|
||
{
|
||
$str = (string)$str;
|
||
if (function_exists('iconv')) {
|
||
$strConverted = @iconv('UTF-8', 'Windows-1252//TRANSLIT', $str);
|
||
if ($strConverted !== false) {
|
||
return $strConverted;
|
||
}
|
||
}
|
||
if (function_exists('mb_convert_encoding')) {
|
||
return (string)mb_convert_encoding($str, 'Windows-1252', 'UTF-8');
|
||
}
|
||
|
||
return $str;
|
||
}
|
||
|
||
/** Droit impression (hors kit total). */
|
||
function fxDossardPrintCan($intComId, $intEveId)
|
||
{
|
||
if (!function_exists('fxEveAccesHasPermission')) {
|
||
require_once __DIR__ . '/inc_fx_eve_acces.php';
|
||
}
|
||
|
||
return fxEveAccesHasPermission(intval($intComId), intval($intEveId), MSIN_DOSSARD_PRINT_PERM);
|
||
}
|
||
|
||
/**
|
||
* @return array|null
|
||
*/
|
||
function fxDossardPrintLoadParticipant($intParId, $intEveId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$intParId = intval($intParId);
|
||
$intEveId = intval($intEveId);
|
||
if ($intParId <= 0 || $intEveId <= 0) {
|
||
return null;
|
||
}
|
||
|
||
$sql = 'SELECT p.par_id, p.par_prenom, p.par_nom, p.no_bib, p.eve_id, p.epr_id, p.pec_id,
|
||
e.pec_id_original, e.pec_actif, e.is_cancelled
|
||
FROM resultats_participants p
|
||
INNER JOIN resultats_epreuves_commandees e
|
||
ON e.pec_id_original = p.pec_id AND e.epr_id = p.epr_id
|
||
WHERE p.par_id = ' . $intParId . '
|
||
AND p.eve_id = ' . $intEveId . '
|
||
LIMIT 1';
|
||
|
||
$row = $objDatabase->fxGetRow($sql);
|
||
|
||
return ($row === null || $row === false) ? null : $row;
|
||
}
|
||
|
||
function fxDossardPrintQrUrl($intEveId)
|
||
{
|
||
if (!function_exists('fxKcEveResultatsQrUrl')) {
|
||
require_once __DIR__ . '/inc_fx_eve_extra.php';
|
||
}
|
||
|
||
return fxKcEveResultatsQrUrl(intval($intEveId));
|
||
}
|
||
|
||
/**
|
||
* @return string|false chemin PNG temp
|
||
*/
|
||
function fxDossardPrintBuildQrTempFile($intEveId)
|
||
{
|
||
require_once __DIR__ . '/../libs/phpqrcode-master/qrlib.php';
|
||
|
||
$strUrl = fxDossardPrintQrUrl($intEveId);
|
||
if ($strUrl === '') {
|
||
return false;
|
||
}
|
||
|
||
$strTmp = tempnam(sys_get_temp_dir(), 'ms1dossardqr_');
|
||
if ($strTmp === false) {
|
||
return false;
|
||
}
|
||
$strPng = $strTmp . '.png';
|
||
@unlink($strTmp);
|
||
|
||
QRcode::png($strUrl, $strPng, QR_ECLEVEL_M, 6, 1);
|
||
if (!is_file($strPng)) {
|
||
return false;
|
||
}
|
||
|
||
return $strPng;
|
||
}
|
||
|
||
/**
|
||
* Layout page 8.5" × 5.5" (mm) + overlays.
|
||
* Coordonnées calibrées pour le template comic (case QR bas-droite).
|
||
*
|
||
* @return array<string,mixed>
|
||
*/
|
||
function fxDossardPrintLayout()
|
||
{
|
||
$arrSize = fxDossardPrintPageSizeMm();
|
||
$fltW = $arrSize[0]; // 215.9
|
||
$fltH = $arrSize[1]; // 139.7
|
||
|
||
// Case QR du design : bas-droite (~1.1" dans le cadre)
|
||
$fltQr = 28.0;
|
||
|
||
return array(
|
||
'page_w' => $fltW,
|
||
'page_h' => $fltH,
|
||
// N° centré dans la zone blanche centrale
|
||
'bib_y' => 52,
|
||
'bib_font' => 72,
|
||
'bib_h' => 28,
|
||
// Nom sous le numéro
|
||
'name_y' => 84,
|
||
'name_font' => 14,
|
||
// QR dans la case « SCANNEZ POUR RÉSULTATS »
|
||
'qr_size' => $fltQr,
|
||
'qr_x' => $fltW - $fltQr - 11.5,
|
||
'qr_y' => $fltH - $fltQr - 14.5,
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Génère et envoie le PDF (exit).
|
||
*
|
||
* @param array $arrRow
|
||
*/
|
||
function fxDossardPrintOutputPdf($arrRow)
|
||
{
|
||
$intEveId = intval($arrRow['eve_id'] ?? 0);
|
||
$strTemplate = fxDossardPrintResolveTemplatePath($intEveId);
|
||
if ($strTemplate === null) {
|
||
http_response_code(500);
|
||
header('Content-Type: text/plain; charset=utf-8');
|
||
echo 'Template dossard introuvable (assets/dossard_templates/default.jpg).';
|
||
exit;
|
||
}
|
||
|
||
$strFpdf = dirname(__DIR__) . '/fpdf182/fpdf.php';
|
||
if (!is_file($strFpdf)) {
|
||
$strDocRoot = $_SERVER['DOCUMENT_ROOT'] ?? '';
|
||
$strFpdf = rtrim((string)$strDocRoot, '/\\') . '/fpdf182/fpdf.php';
|
||
}
|
||
if (!is_file($strFpdf)) {
|
||
http_response_code(500);
|
||
header('Content-Type: text/plain; charset=utf-8');
|
||
echo 'FPDF introuvable (fpdf182/fpdf.php).';
|
||
exit;
|
||
}
|
||
require_once $strFpdf;
|
||
|
||
$arrLayout = fxDossardPrintLayout();
|
||
$strBib = trim((string)($arrRow['no_bib'] ?? ''));
|
||
if ($strBib === '' || $strBib === '0') {
|
||
$strBib = '-';
|
||
}
|
||
$strPrenom = trim(function_exists('fxUnescape') ? fxUnescape($arrRow['par_prenom'] ?? '') : (string)($arrRow['par_prenom'] ?? ''));
|
||
$strNom = trim(function_exists('fxUnescape') ? fxUnescape($arrRow['par_nom'] ?? '') : (string)($arrRow['par_nom'] ?? ''));
|
||
$strName = trim($strPrenom . ' ' . $strNom);
|
||
|
||
$strQrFile = fxDossardPrintBuildQrTempFile($intEveId);
|
||
$strTplType = fxDossardPrintImageType($strTemplate);
|
||
|
||
// Page = feuille coupée 8.5" × 5.5".
|
||
// FPDF (_getpagesize) range si w>h ; 'L' remet w=8.5 h=5.5.
|
||
$pdf = new FPDF('L', 'mm', array($arrLayout['page_w'], $arrLayout['page_h']));
|
||
$pdf->SetAutoPageBreak(false);
|
||
$pdf->SetMargins(0, 0, 0);
|
||
$pdf->AddPage();
|
||
|
||
// Fond pleine page — ratio template ≈ 8.5:5.5 → pas de déformation
|
||
$pdf->Image(
|
||
$strTemplate,
|
||
0,
|
||
0,
|
||
$arrLayout['page_w'],
|
||
$arrLayout['page_h'],
|
||
$strTplType
|
||
);
|
||
|
||
// Numéro
|
||
$pdf->SetTextColor(0, 0, 0);
|
||
$pdf->SetFont('Helvetica', 'B', intval($arrLayout['bib_font']));
|
||
$pdf->SetXY(20, $arrLayout['bib_y']);
|
||
$pdf->Cell(
|
||
$arrLayout['page_w'] - 40,
|
||
$arrLayout['bib_h'],
|
||
fxDossardPrintPdfText($strBib),
|
||
0,
|
||
0,
|
||
'C'
|
||
);
|
||
|
||
// Nom
|
||
if ($strName !== '') {
|
||
$pdf->SetFont('Helvetica', 'B', intval($arrLayout['name_font']));
|
||
$pdf->SetXY(20, $arrLayout['name_y']);
|
||
$pdf->Cell($arrLayout['page_w'] - 40, 8, fxDossardPrintPdfText($strName), 0, 0, 'C');
|
||
}
|
||
|
||
// QR dans la case du template
|
||
if ($strQrFile !== false) {
|
||
$pdf->Image(
|
||
$strQrFile,
|
||
$arrLayout['qr_x'],
|
||
$arrLayout['qr_y'],
|
||
$arrLayout['qr_size'],
|
||
$arrLayout['qr_size'],
|
||
'PNG'
|
||
);
|
||
@unlink($strQrFile);
|
||
}
|
||
|
||
$strSafeBib = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $strBib);
|
||
$strFilename = 'dossard-' . $strSafeBib . '-par' . intval($arrRow['par_id']) . '.pdf';
|
||
|
||
$pdf->Output('I', $strFilename);
|
||
exit;
|
||
}
|