Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
47.24% covered (danger)
47.24%
60 / 127
0.00% covered (danger)
0.00%
0 / 2
CRAP
n/a
0 / 0
qrcodes_generate_sticker
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 1
72
qrcodes_generate_pdf
44.00% covered (danger)
44.00%
22 / 50
0.00% covered (danger)
0.00%
0 / 1
67.75
1<?php
2
3/**
4 * @file
5 * Place action: generate QR sticker PDF (qrcodes).
6 */
7
8declare(strict_types=1);
9
10require_once __DIR__.'/../../Legacy/common/session.php';
11require_once __DIR__.'/../legacy/model/spec/sticker.php';
12require_once __DIR__.'/../../Legacy/depends/dompdf/autoload.inc.php';
13
14use Dompdf\Dompdf;
15
16/**
17 * @param array<string, mixed> $qrcode
18 * @param string $lang
19 * @param string|null $dstpath Output path.
20 */
21function qrcodes_generate_sticker(array &$qrcode, string $lang, ?string &$dstpath): int
22{
23    $retval = \ApplicationError::Success;
24    $srcname = __DIR__.'/../../Legacy/image/sticker.png';
25    if (!file_exists($srcname)) {
26        \addlog(__FILE__, \LogLevel::Error, "Source image for sticker not found at '".$srcname."'");
27        return \ApplicationError::NotFound;
28    }
29    $image_info = getimagesize($srcname);
30    $tpeimage = imagecreatefrompng($srcname);
31    if (!$tpeimage) {
32        return \ApplicationError::Unknown;
33    }
34
35    $retval = \generateQRFlatImage($qrcode['objid'], $qrcode['number'], $qrcode['authorization'], $lang);
36    if (!\success($retval)) {
37        \addlog(__FILE__, \LogLevel::Error, "Could not generate qrcode sticker (errorcode: ".$retval.")");
38        return $retval;
39    }
40    $srcflat = \AppConstants::QrCodePath()."/qr_".$qrcode['objid']."_flat.png";
41    $image_info = getimagesize($srcflat);
42    $srcimage = imagecreatefrompng($srcflat);
43    if (!$srcimage) {
44        return \ApplicationError::Unknown;
45    }
46
47    $dstx = 45;
48    $dsty = 235;
49    $dstw = 438;
50    $dsth = 520;
51    $qrcodew = $image_info[0];
52    $qrcodeh = $image_info[1];
53    $res = imagecopyresampled($tpeimage, $srcimage, $dstx, $dsty, 0, 0, $dstw, $dsth, $qrcodew, $qrcodeh);
54    if (!$res) {
55        \addlog(__FILE__, \LogLevel::Error, "Merge of qrcode on sticker image failed");
56        return \ApplicationError::Unknown;
57    }
58
59    $relativepath = tempnam(\AppConstants::QrCodePath(), "tmp");
60    $res = chmod($relativepath, 0666) && (imagepng($tpeimage, $relativepath));
61    if (!$res) {
62        \addlog(__FILE__, \LogLevel::Information, "Could not save destination file in: '".$relativepath."'");
63        return \ApplicationError::Unknown;
64    }
65    $dstpath = realpath($relativepath);
66    return $retval;
67}
68
69/**
70 * @param string|int $place
71 * @param string $lang
72 * @param array<int, array<string, mixed>> $qrcodes
73 * @param string|null $pdfurl Output URL.
74 */
75function qrcodes_generate_pdf($place, string $lang, array &$qrcodes, ?string &$pdfurl): int
76{
77    $retval = \ApplicationError::Success;
78    foreach ($qrcodes as &$qrcode) {
79        if (\success($retval)) {
80            $retval = qrcodes_generate_sticker($qrcode, $lang, $qrcode['sticker']);
81        }
82    }
83    unset($qrcode);
84
85    if (!\success($retval)) {
86        return $retval;
87    }
88    $rows = [];
89    foreach ($qrcodes as $i => $qrcode) {
90        $row = (int) ($i / 4);
91        if (!isset($rows[$row])) {
92            $rows[$row] = [];
93        }
94        $rows[$row][] = $qrcode;
95    }
96    $pages = [];
97    foreach ($rows as $i => $row) {
98        $pag = (int) ($i / 3);
99        if (!isset($pages[$pag])) {
100            $pages[$pag] = [];
101        }
102        $pages[$pag][] = $row;
103    }
104
105    $html = "<!DOCTYPE html>\n<html>\n<head><title>pdf stickers</title></head><body>\n";
106    foreach ($pages as $page) {
107        $html .= "<table>\n";
108        foreach ($page as $row) {
109            $html .= "<tr>\n";
110            foreach ($row as $qrcode) {
111                if (file_exists($qrcode['sticker'])) {
112                    $data = file_get_contents($qrcode['sticker']);
113                    $b64d = "data:image/png;base64,".base64_encode($data);
114                    $html .= "<td style='border:1px dashed #666; padding:10px 10px'>\n";
115                    $html .= "<img src='".$b64d."' height='300'>\n</td>\n";
116                } else {
117                    \addlog(__FILE__, \LogLevel::Error, "Image file '".$qrcode['sticker']."' not found.");
118                    $retval = \ApplicationError::NotFound;
119                }
120            }
121            $html .= "</tr>\n";
122        }
123        $html .= "</table>\n<hr style='page-break-after: always; border: 0; margin: 0; padding: 0;'/>\n";
124    }
125    $html .= "</body>\n</html>";
126
127    $dompdf = new Dompdf();
128    $dompdf->loadHtml(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
129    $dompdf->setPaper('A4', 'portrait');
130    $dompdf->render();
131    $dstpath = \AppConstants::QrCodePath()."/qr_sticker_".$place.".pdf";
132    if (!file_put_contents($dstpath, $dompdf->output())) {
133        \addlog(__FILE__, \LogLevel::Error, "Could not save destination pdf file in: '".$dstpath."'");
134        $retval = \ApplicationError::Unknown;
135    }
136
137    foreach ($qrcodes as &$qrcode) {
138        if (isset($qrcode['sticker']) && file_exists($qrcode['sticker'])) {
139            unlink($qrcode['sticker']);
140        }
141    }
142    unset($qrcode);
143
144    if (\success($retval)) {
145        $pdfurl = \AppConstants::QrCodeUrl()."/qr_sticker_".$place.".pdf";
146    }
147    return $retval;
148}
149
150/**
151 * Action callable: generate QR sticker PDF for place.
152 *
153 * @param string $body Unused.
154 * @param array<string, mixed> $query Query params: device, session, place, lang.
155 * @param \ConxHelper $conx Connection helper.
156 * @param \Psr\Log\LoggerInterface $logger Logger.
157 * @param \UppServices\SessionService $sessionService Session service for check.
158 * @return array{output: string, contentType: string}
159 */
160return function (string $body, array $query, \ConxHelper $conx, \Psr\Log\LoggerInterface $logger, \UppServices\SessionService $sessionService): array {
161    $retval = \ApplicationError::Success;
162    $place = null;
163
164    $device = $query['device'] ?? null;
165    if (!$device) {
166        $logger->error("No device provided on URL. Operation cancelled.");
167        $retval = \ApplicationError::Parameters;
168    }
169
170    if (\success($retval)) {
171        $session = $query['session'] ?? null;
172        if (!$session) {
173            $logger->error("No session provided on URL. Operation cancelled.");
174            $retval = \ApplicationError::Parameters;
175        } else {
176            $userid = null;
177            $retval = $sessionService->checkSession($conx, (string) $session, (string) $device, $userid);
178        }
179    }
180
181    if (\success($retval)) {
182        $place = $query['place'] ?? null;
183        if (!$place) {
184            $logger->error("Mandatory parameter 'place' not provided on URL. Operation cancelled.");
185            $retval = \ApplicationError::Parameters;
186        }
187    }
188
189    if (\success($retval)) {
190        $lang = $query['lang'] ?? null;
191        if (!$lang) {
192            $logger->error("Mandatory parameter 'lang' not provided on URL. Operation cancelled.");
193            $retval = \ApplicationError::Parameters;
194        }
195    }
196
197    $qrcodes = [];
198    if (\success($retval)) {
199        $res = $conx->global->query('QRSCAN', ['place' => (int) $place, 'status' => 'AC'], $qrcodes);
200        if (!$res) {
201            $logger->error("QRSCAN query failed for place ".$place);
202            $retval = \ApplicationError::Database;
203        }
204    }
205
206    $pdfurl = null;
207    if (\success($retval)) {
208        $retval = qrcodes_generate_pdf($place, (string) $lang, $qrcodes, $pdfurl);
209    }
210
211    $result = [
212        "errorcode" => $retval,
213        "pdfurl" => \success($retval) ? $pdfurl : null,
214    ];
215    return ['output' => json_encode($result), 'contentType' => 'application/json; charset=utf-8'];
216};