Passed
Push — master ( 17bffe...10bee5 )
by Stefan
06:13
created

UIElements::boxOkay()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 2
c 0
b 0
f 0
rs 10
cc 1
eloc 1
nc 1
nop 3
1
<?php
2
3
/*
4
 * ******************************************************************************
5
 * Copyright 2011-2017 DANTE Ltd. and GÉANT on behalf of the GN3, GN3+, GN4-1 
6
 * and GN4-2 consortia
7
 *
8
 * License: see the web/copyright.php file in the file structure
9
 * ******************************************************************************
10
 */
11
12
namespace web\lib\admin;
13
use Exception;
14
15
/**
16
 * This class provides various HTML snippets and other UI-related convenience functions.
17
 * 
18
 * @author Stefan Winter <[email protected]>
19
 */
20
class UIElements {
21
22
    /**
23
     * the custom displayable variant of the term 'federation'
24
     * 
25
     * @var string
26
     */
27
    public $nomenclature_fed;
28
29
    /**
30
     * the custom displayable variant of the term 'institution'
31
     * 
32
     * @var string
33
     */
34
    public $nomenclature_inst;
35
36
    /**
37
     * Initialises the class.
38
     * 
39
     * Mainly fetches various nomenclature from the config and attempts to translate those into local language. Needs pre-loading some terms.
40
     */
41 View Code Duplication
    public function __construct() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
42
        // some config elements are displayable. We need some dummies to 
43
        // translate the common values for them. If a deployment chooses a 
44
        // different wording, no translation, sorry
45
46
        $dummy_NRO = _("National Roaming Operator");
47
        $dummy_inst1 = _("identity provider");
48
        $dummy_inst2 = _("organisation");
49
        // and do something useless with the strings so that there's no "unused" complaint
50
        if ( $dummy_NRO . $dummy_inst1 . $dummy_inst2 == "") {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
51
            // Oh well.
52
        }
53
        $this->nomenclature_fed = _(CONFIG_CONFASSISTANT['CONSORTIUM']['nomenclature_federation']);
54
        $this->nomenclature_inst = _(CONFIG_CONFASSISTANT['CONSORTIUM']['nomenclature_institution']);
55
    }
56
57
    /**
58
     * provides human-readable text for the various option names as stored in DB.
59
     * 
60
     * @param string $input raw text in need of a human-readable display variant
61
     * @return string the human-readable variant
62
     * @throws Exception
63
     */
64
    public function displayName($input) {
65
66
        $ssidText = _("SSID");
67
        $ssidLegacyText = _("SSID (with WPA/TKIP)");
68
        $passpointOiText = _("HS20 Consortium OI");
69
70 View Code Duplication
        if (count(CONFIG_CONFASSISTANT['CONSORTIUM']['ssid']) > 0) {
71
            $ssidText = _("Additional SSID");
72
            $ssidLegacyText = _("Additional SSID (with WPA/TKIP)");
73
        }
74
        if (!empty(CONFIG_CONFASSISTANT['CONSORTIUM']['interworking-consortium-oi']) && count(CONFIG_CONFASSISTANT['CONSORTIUM']['interworking-consortium-oi']) > 0) {
75
            $passpointOiText = _("Additional HS20 Consortium OI");
76
        }
77
78
        $displayNames = [_("Support: Web") => "support:url",
79
            _("Support: EAP Types") => "support:eap_types",
80
            _("Support: Phone") => "support:phone",
81
            _("Support: E-Mail") => "support:email",
82
            sprintf(_("Name of %s"), $this->nomenclature_inst) => "general:instname",
83
            _("Location") => "general:geo_coordinates",
84
            _("Logo URL") => "general:logo_url",
85
            _("Logo image") => "general:logo_file",
86
            _("Configure Wired Ethernet") => "media:wired",
87
            _("Name (CN) of Authentication Server") => "eap:server_name",
88
            _("Enable device assessment") => "eap:enable_nea",
89
            _("Terms of Use") => "support:info_file",
90
            _("CA Certificate URL") => "eap:ca_url",
91
            _("CA Certificate File") => "eap:ca_file",
92
            _("Profile Display Name") => "profile:name",
93
            _("Production-Ready") => "profile:production",
94
            _("Admin Accepted Terms of Use") => 'hiddenprofile:tou_accepted',
95
            _("Extra text on downloadpage for device") => "device-specific:customtext",
96
            _("Redirection Target") => "device-specific:redirect",
97
            _("Extra text on downloadpage for EAP method") => "eap-specific:customtext",
98
            _("Turn on selection of EAP-TLS User-Name") => "eap-specific:tls_use_other_id",
99
            _("Profile Description") => "profile:description",
100
            _("Custom Installer Name Suffix") => "profile:customsuffix",
101
            sprintf(_("%s Administrator"), $this->nomenclature_fed) => "user:fedadmin",
102
            _("Real Name") => "user:realname",
103
            _("E-Mail Address") => "user:email",
104
            _("Remove/Disable SSID") => "media:remove_SSID",
105
            _("Custom CSS file for User Area") => "fed:css_file",
106
            sprintf(_("%s Logo"), $this->nomenclature_fed) => "fed:logo_file",
107
            _("Preferred Skin for User Area") => "fed:desired_skin",
108
            _("Include NRO branding in installers") => "fed:include_logo_installers",
109
            sprintf(_("%s Name"), $this->nomenclature_fed) => "fed:realname",
110
            _("Custom text in IdP Invitations") => "fed:custominvite",
111
            sprintf(_("Enable %s"), \core\ProfileSilverbullet::PRODUCTNAME) => "fed:silverbullet",
112
            sprintf(_("%s: Do not terminate EAP"), \core\ProfileSilverbullet::PRODUCTNAME) => "fed:silverbullet-noterm",
113
            sprintf(_("%s: max users per profile"), \core\ProfileSilverbullet::PRODUCTNAME) => "fed:silverbullet-maxusers",
114
            $ssidText => "media:SSID",
115
            $ssidLegacyText => "media:SSID_with_legacy",
116
            $passpointOiText => "media:consortium_OI",
117
        ];
118
119
        $find = array_keys($displayNames, $input, TRUE);
120
121
        if (count($find) == 0) { // this is an error! throw an Exception
122
            throw new \Exception("The translation of an option name was requested, but the option is not known to the system: " . htmlentities($input));
123
        }
124
        return $find[0];
125
    }
126
127
    public function tooltip($input) {
128
        $descriptions = [];
129
        if (count(CONFIG_CONFASSISTANT['CONSORTIUM']['ssid']) > 0) {
130
            $descriptions[sprintf(_("This attribute can be set if you want to configure an additional SSID besides the default SSIDs for %s. It is almost always a bad idea not to use the default SSIDs. The only exception is if you have premises with an overlap of the radio signal with another %s hotspot. Typical misconceptions about additional SSIDs include: I want to have a local SSID for my own users. It is much better to use the default SSID and separate user groups with VLANs. That approach has two advantages: 1) your users will configure %s properly because it is their everyday SSID; 2) if you use a custom name and advertise this one as extra secure, your users might at some point roam to another place which happens to have the same SSID name. They might then be misled to believe that they are connecting to an extra secure network while they are not."), CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'], CONFIG_CONFASSISTANT['CONSORTIUM']['display_name'])] = "media:SSID";
131
        }
132
133
        $find = array_search($input, $descriptions);
134
135
        if ($find === FALSE) {
136
            return "";
137
        }
138
        return "<span class='tooltip' onclick='alert(\"" . $find . "\")'><img src='../resources/images/icons/question-mark-icon.png" . "'></span>";
139
    }
140
141
    /**
142
     * creates an HTML information block with a list of options from a given category and level
143
     * @param array $optionlist list of options
144
     * @param string $class option class of interest
145
     * @param string $level option level of interest
146
     * @return string HTML code
147
     */
148
    public function infoblock(array $optionlist, string $class, string $level) {
149
        $googleMarkers = [];
150
        $retval = "";
151
        $optioninfo = \core\Options::instance();
152
153
        foreach ($optionlist as $option) {
154
            $type = $optioninfo->optionType($option['name']);
155
            if (preg_match('/^' . $class . '/', $option['name']) && $option['level'] == "$level") {
156
                // all non-multilang attribs get this assignment ...
157
                $language = "";
158
                $content = $option['value'];
159
                // ... override them with multilang tags if needed
160
                if ($type["flag"] == "ML") {
161
                    $language = _("default/other languages");
162 View Code Duplication
                    if ($option['lang'] != 'C') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163
                        $language = CONFIG['LANGUAGES'][$option['lang']]['display'] ?? "(unsupported language)";
164
                    }
165
                }
166
167
                switch ($type["type"]) {
168
                    case "coordinates":
169
                        $coords = json_decode($option['value'], true);
170
                        $googleMarkers[] = $coords;
171
                        break;
172
                    case "file":
173
                        $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td>";
174
                        switch ($option['name']) {
175
                            case "general:logo_file":
176
                            case "fed:logo_file":
177
                                $retval .= $this->previewImageinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
178
                                break;
179
                            case "eap:ca_file":
180
                                $retval .= $this->previewCAinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
181
                                break;
182
                            case "support:info_file":
183
                                $retval .= $this->previewInfoFileinHTML('ROWID-' . $option['level'] . '-' . $option['row']);
184
                                break;
185
                            default:
186
                        }
187
                        break;
188
                    case "boolean":
189
                        $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td><strong>" . ($content == "on" ? _("on") : _("off") ) . "</strong></td></tr>";
190
                        break;
191
                    default:
192
                        $retval .= "<tr><td>" . $this->displayName($option['name']) . "</td><td>$language</td><td><strong>$content</strong></td></tr>";
193
                }
194
            }
195
        }
196
        if (count($googleMarkers)) {
197
            $marker = '<markers>';
198
            $locationCount = 0;
199
            foreach ($googleMarkers as $g) {
200
                $locationCount++;
201
                $marker .= '<marker name="' . $locationCount . '" lat="' . $g['lat'] . '" lng="' . $g['lon'] . '" />';
202
            }
203
            $marker .= '</markers>';
204
            $retval .= '<tr><td><script>markers=\'' . $marker . '\';</script></td><td></td><td></td></tr>';
205
        }
206
        return $retval;
207
    }
208
209
    /**
210
     * creates HTML code to display all information boxes for an IdP
211
     * 
212
     * @param \core\IdP $myInst the IdP in question
213
     * @return string HTML code
214
     */
215
    public function instLevelInfoBoxes(\core\IdP $myInst) {
216
        $idpoptions = $myInst->getAttributes();
217
        $retval = "<div class='infobox'>
218
        <h2>" . sprintf(_("General %s details"), $this->nomenclature_inst) . "</h2>
219
        <table>
220
            <tr>
221
                <td>
222
                    " . _("Country:") . "
223
                </td>
224
                <td>
225
                </td>
226
                <td>
227
                    <strong>";
228
        $myFed = new \core\Federation($myInst->federation);
229
        $retval .= $myFed->name;
230
        $retval .= "</strong>
231
                </td>
232
            </tr>" . $this->infoblock($idpoptions, "general", "IdP") . "
233
        </table>
234
    </div>";
235
236
        $blocks = [["support", _("Global Helpdesk Details")], ["media", _("Media Properties")]];
237
        foreach ($blocks as $block) {
238
            $retval .= "<div class='infobox'>
239
            <h2>" . $block[1] . "</h2>
240
            <table>" .
241
                    $this->infoblock($idpoptions, $block[0], "IdP") .
242
                    "</table>
243
        </div>";
244
        }
245
        return $retval;
246
    }
247
248
    /**
249
     * pretty-prints a file size number in SI "bi" units
250
     * @param int $number the size of the file
251
     * @return string the pretty-print representation of the file size
252
     */
253
    private function displaySize(int $number) {
254
        if ($number > 1024 * 1024) {
255
            return round($number / 1024 / 1024, 2) . " MiB";
256
        }
257
        if ($number > 1024) {
258
            return round($number / 1024, 2) . " KiB";
259
        }
260
        return $number . " B";
261
    }
262
263
    /**
264
     * 
265
     * @param string $ref the database reference string
266
     * @param boolean $checkpublic should we check if the requested piece of data is public?
267
     * @return string|FALSE the requested data, or FALSE if something went wrong
268
     */
269
    public static function getBlobFromDB($ref, $checkpublic) {
270
        $validator = new \web\lib\common\InputValidation();
271
        $reference = $validator->databaseReference($ref);
272
273
        if ($reference == FALSE) {
274
            return FALSE;
275
        }
276
277
        // the data is either public (just give it away) or not; in this case, only
278
        // release if the data belongs to admin himself
279
        if ($checkpublic) {
280
            // we might be called without session context (filepreview) so get the
281
            // context if needed
282
            if (session_status() != PHP_SESSION_ACTIVE) {
283
                session_start();
284
            }
285
            $owners = \core\EntityWithDBProperties::isDataRestricted($reference["table"], $reference["rowindex"]);
286
287
            $ownersCondensed = [];
288
289
            if ($owners !== FALSE) { // restricted datam see if we're authenticated and owners of the data
290
                $auth = new \web\lib\admin\Authentication();
291
                if (!$auth->isAuthenticated()) {
292
                    return FALSE; // admin-only, but we are not an admin
293
                }
294
                foreach ($owners as $oneowner) {
295
                    $ownersCondensed[] = $oneowner['ID'];
296
                }
297
                if (array_search($_SESSION['user'], $ownersCondensed) === FALSE) {
298
                    return FALSE; // wrong guy
299
                }
300
                // carry on and get the data
301
            }
302
        }
303
304
        $blob = \core\EntityWithDBProperties::fetchRawDataByIndex($reference["table"], $reference["rowindex"]);
305
        return $blob; // this means we might return FALSE here if something was wrong with the original requested reference
306
    }
307
308
    /**
309
     * 
310
     * @param string $reference a reference pointer to a database entry
311
     * @throws Exception
312
     */
313
    
314
    private function checkROWIDpresence($reference) {
315
        $found = preg_match("/^ROWID-.*/", $reference);
316
        if ($found  != 1) { // get excited on not-found AND on execution error
317
            throw new Exception("Error, ROWID expected.");
318
        }
319
    }
320
    
321
    /**
322
     * creates HTML code to display a nice UI representation of a CA
323
     * 
324
     * @param string $cAReference ROWID pointer to the CA to display
325
     * @return string HTML code
326
     */
327
    public function previewCAinHTML($cAReference) {
328
        $this->checkROWIDpresence($cAReference);
329
        $cAblob = base64_decode(UIElements::getBlobFromDB($cAReference, FALSE));
0 ignored issues
show
Bug introduced by
web\lib\admin\UIElements...DB($cAReference, FALSE) of type false is incompatible with the type string expected by parameter $data of base64_decode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

329
        $cAblob = base64_decode(/** @scrutinizer ignore-type */ UIElements::getBlobFromDB($cAReference, FALSE));
Loading history...
330
331
        $func = new \core\common\X509;
332
        $details = $func->processCertificate($cAblob);
333
        if ($details === FALSE) {
334
            return _("There was an error processing the certificate!");
335
        }
336
337
        $details['name'] = preg_replace('/(.)\/(.)/', "$1<br/>$2", $details['name']);
338
        $details['name'] = preg_replace('/\//', "", $details['name']);
339
        $certstatus = ( $details['root'] == 1 ? "R" : "I");
340
        if ($details['ca'] == 0 && $details['root'] != 1) {
341
            return "<div class='ca-summary' style='background-color:red'><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:maroon;  border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>S</div></div>" . _("This is a <strong>SERVER</strong> certificate!") . "<br/>" . $details['name'] . "</div>";
342
        }
343
        return "<div class='ca-summary'                                ><div style='position:absolute; right: 0px; width:20px; height:20px; background-color:#0000ff; border-radius:10px; text-align: center;'><div style='padding-top:3px; font-weight:bold; color:#ffffff;'>$certstatus</div></div>" . $details['name'] . "</div>";
344
    }
345
346
    /**
347
     * creates HTML code to display a nice UI representation of an image
348
     * 
349
     * @param string $imageReference ROWID pointer to the image to display
350
     * @return string HTML code
351
     */
352
    public function previewImageinHTML($imageReference) {
353
        $this->checkROWIDpresence($imageReference);
354
        return "<img style='max-width:150px' src='inc/filepreview.php?id=" . $imageReference . "' alt='" . _("Preview of logo file") . "'/>";
355
    }
356
357
    /**
358
     * creates HTML code to display a nice UI representation of a TermsOfUse file
359
     * 
360
     * @param string $fileReference ROWID pointer to the file to display
361
     * @return string HTML code
362
     */
363
    public function previewInfoFileinHTML($fileReference) {
364
        $this->checkROWIDpresence($fileReference);
365
        $fileBlob = UIElements::getBlobFromDB($fileReference, FALSE);
366
        $decodedFileBlob = base64_decode($fileBlob);
0 ignored issues
show
Bug introduced by
$fileBlob of type false is incompatible with the type string expected by parameter $data of base64_decode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

366
        $decodedFileBlob = base64_decode(/** @scrutinizer ignore-type */ $fileBlob);
Loading history...
367
        $fileinfo = new \finfo();
0 ignored issues
show
Bug introduced by
The call to finfo::finfo() has too few arguments starting with options. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

367
        $fileinfo = /** @scrutinizer ignore-call */ new \finfo();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
368
        return "<div class='ca-summary'>" . _("File exists") . " (" . $fileinfo->buffer($decodedFileBlob, FILEINFO_MIME_TYPE) . ", " . $this->displaySize(strlen($decodedFileBlob)) . ")<br/><a href='inc/filepreview.php?id=$fileReference'>" . _("Preview") . "</a></div>";
369
    }
370
371
    /**
372
     * creates HTML code for a UI element which informs the user about something.
373
     * 
374
     * @param int $level what kind of information is to be displayed?
375
     * @param string $text the text to display
376
     * @param string $caption the caption to display
377
     * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them
378
     * @return string
379
     */
380
    public function boxFlexible(int $level, string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) {
381
382
        $uiMessages = [
383
            \core\common\Entity::L_OK => ['icon' => '../resources/images/icons/Quetto/check-icon.png', 'text' => _("OK")],
384
            \core\common\Entity::L_REMARK => ['icon' => '../resources/images/icons/Quetto/info-icon.png', 'text' => _("Remark")],
385
            \core\common\Entity::L_WARN => ['icon' => '../resources/images/icons/Quetto/danger-icon.png', 'text' => _("Warning!")],
386
            \core\common\Entity::L_ERROR => ['icon' => '../resources/images/icons/Quetto/no-icon.png', 'text' => _("Error!")],
387
        ];
388
389
        $retval = "";
390
        if (!$omittabletags) {
391
            $retval .= "<tr><td>";
392
        }
393
        $finalCaption = ($caption !== NULL ? $caption : $uiMessages[$level]['text']);
394
        $retval .= "<img class='icon' src='" . $uiMessages[$level]['icon'] . "' alt='" . $finalCaption . "' title='" . $finalCaption . "'/>";
395
        if (!$omittabletags) {
396
            $retval .= "</td><td>";
397
        }
398
        if ($text !== NULL) {
399
            $retval .= $text;
400
        }
401
        if (!$omittabletags) {
402
            $retval .= "</td></tr>";
403
        }
404
        return $retval;
405
    }
406
407
    /**
408
     * creates HTML code to display an "all is okay" message
409
     * 
410
     * @param string $text the text to display
411
     * @param string $caption the caption to display
412
     * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them
413
     * @return string HTML: the box
414
     */
415
    public function boxOkay(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) {
416
        return $this->boxFlexible(\core\common\Entity::L_OK, $text, $caption, $omittabletags);
417
    }
418
419
    /**
420
     * creates HTML code to display a "smartass comment" message
421
     * 
422
     * @param string $text the text to display
423
     * @param string $caption the caption to display
424
     * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them
425
     * @return string HTML: the box
426
     */
427
    public function boxRemark(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) {
428
        return $this->boxFlexible(\core\common\Entity::L_REMARK, $text, $caption, $omittabletags);
429
    }
430
431
    /**
432
     * creates HTML code to display a "something's a bit wrong" message
433
     * 
434
     * @param string $text the text to display
435
     * @param string $caption the caption to display
436
     * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them
437
     * @return string HTML: the box
438
     */
439
    public function boxWarning(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) {
440
        return $this->boxFlexible(\core\common\Entity::L_WARN, $text, $caption, $omittabletags);
441
    }
442
443
    /**
444
     * creates HTML code to display a "Whoa! Danger, Will Robinson!" message
445
     * 
446
     * @param string $text the text to display
447
     * @param string $caption the caption to display
448
     * @param bool $omittabletags the output usually has tr/td table tags, this option suppresses them
449
     * @return string HTML: the box
450
     */
451
    public function boxError(string $text = NULL, string $caption = NULL, bool $omittabletags = FALSE) {
452
        return $this->boxFlexible(\core\common\Entity::L_ERROR, $text, $caption, $omittabletags);
453
    }
454
455
    /**
456
     * Injects the consortium logo in the middle of a given PNG.
457
     * 
458
     * Usually used on QR code PNGs - the parameters inform about the structure of
459
     * the QR code so that the logo does not prevent parsing of the QR code.
460
     * 
461
     * @param string $inputpngstring the PNG to edit
462
     * @param int $symbolsize size in pixels of one QR "pixel"
463
     * @param int $marginsymbols size in pixels of border around the actual QR
464
     * @return string the image with logo centered in the middle
465
     */
466
    public function pngInjectConsortiumLogo(string $inputpngstring, int $symbolsize, int $marginsymbols = 4) {
467
        $loggerInstance = new \core\common\Logging();
468
        $inputgd = imagecreatefromstring($inputpngstring);
469
470
        $loggerInstance->debug(4, "Consortium logo is at: " . ROOT . "/web/resources/images/consortium_logo_large.png");
471
        $logogd = imagecreatefrompng(ROOT . "/web/resources/images/consortium_logo_large.png");
472
473
        $sizeinput = [imagesx($inputgd), imagesy($inputgd)];
474
        $sizelogo = [imagesx($logogd), imagesy($logogd)];
475
        // Q level QR-codes can sustain 25% "damage"
476
        // make our logo cover approx 15% of area to be sure; mind that there's a $symbolsize * $marginsymbols pixel white border around each edge
477
        $totalpixels = ($sizeinput[0] - $symbolsize * $marginsymbols) * ($sizeinput[1] - $symbolsize * $marginsymbols);
478
        $totallogopixels = ($sizelogo[0]) * ($sizelogo[1]);
479
        $maxoccupy = $totalpixels * 0.04;
480
        // find out how much we have to scale down logo to reach 10% QR estate
481
        $scale = sqrt($maxoccupy / $totallogopixels);
482
        $loggerInstance->debug(4, "Scaling info: $scale, $maxoccupy, $totallogopixels\n");
483
        // determine final pixel size - round to multitude of $symbolsize to match exact symbol boundary
484
        $targetwidth = $symbolsize * round($sizelogo[0] * $scale / $symbolsize);
485
        $targetheight = $symbolsize * round($sizelogo[1] * $scale / $symbolsize);
486
        // paint white below the logo, in case it has transparencies (looks bad)
487
        // have one symbol in each direction extra white space
488
        $whiteimage = imagecreate($targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
0 ignored issues
show
Bug introduced by
$targetheight + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $height of imagecreate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

488
        $whiteimage = imagecreate($targetwidth + 2 * $symbolsize, /** @scrutinizer ignore-type */ $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetwidth + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $width of imagecreate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

488
        $whiteimage = imagecreate(/** @scrutinizer ignore-type */ $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
489
        imagecolorallocate($whiteimage, 255, 255, 255);
490
        // also make sure the initial placement is a multitude of 12; otherwise "two half" symbols might be affected
491
        $targetplacementx = $symbolsize * round(($sizeinput[0] / 2 - ($targetwidth - $symbolsize) / 2) / $symbolsize);
492
        $targetplacementy = $symbolsize * round(($sizeinput[1] / 2 - ($targetheight - $symbolsize) / 2) / $symbolsize);
493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
0 ignored issues
show
Bug introduced by
$targetplacementy - $symbolsize of type double is incompatible with the type integer expected by parameter $dst_y of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, /** @scrutinizer ignore-type */ $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetheight + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $dst_h of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, /** @scrutinizer ignore-type */ $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetplacementx - $symbolsize of type double is incompatible with the type integer expected by parameter $dst_x of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, /** @scrutinizer ignore-type */ $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetwidth + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $src_w of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, /** @scrutinizer ignore-type */ $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetwidth + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $dst_w of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, /** @scrutinizer ignore-type */ $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize);
Loading history...
Bug introduced by
$targetheight + 2 * $symbolsize of type double is incompatible with the type integer expected by parameter $src_h of imagecopyresized(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
        imagecopyresized($inputgd, $whiteimage, $targetplacementx - $symbolsize, $targetplacementy - $symbolsize, 0, 0, $targetwidth + 2 * $symbolsize, $targetheight + 2 * $symbolsize, $targetwidth + 2 * $symbolsize, /** @scrutinizer ignore-type */ $targetheight + 2 * $symbolsize);
Loading history...
494
        imagecopyresized($inputgd, $logogd, $targetplacementx, $targetplacementy, 0, 0, $targetwidth, $targetheight, $sizelogo[0], $sizelogo[1]);
495
        ob_start();
496
        imagepng($inputgd);
497
        return ob_get_clean();
498
    }
499
500
}
501