Add QR code type "Wifi" + handle every request in index.php (#27)
QR codes types can now be chosen between the default text mode and the Wifi mode.
The WiFi form is on a dedicated page, and that has been implemented by managing every HTTP request from index.php
For more information about the format used for Wifi QR codes check https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
Co-authored-by: Miraty <miraty+git@antopie.org>
Reviewed-on: #27 (https://code.antopie.org/miraty/libreqr/issues/27)
Reviewed-by: Miraty <miraty@noreply.code.antopie.org>
Co-authored-by: Denise <denisebitca@42l.fr>
Co-committed-by: Denise <denisebitca@42l.fr>
e4491752f2
This commit is contained in:
parent
601def06c0
commit
1df83b89a1
8 changed files with 362 additions and 156 deletions
|
|
@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
|
||||
### Added
|
||||
|
||||
* Wifi QR code type (PR [#27](https://code.antopie.org/miraty/libreqr/pulls/27))<br>
|
||||
**Breaking**: HTTP requests for `wifi` needs to be forwarded to the `index.php` endpoint.<br>
|
||||
To ease with webserver configuration, `index.php` is now able to serve any HTTP ressource that is used in the LibreQR interface. This means that every request can be forwarded to `index.php`.
|
||||
* German localization (PR [#25](https://code.antopie.org/miraty/libreqr/pulls/25))
|
||||
|
||||
## 2.0.1 - 2023-07-08
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ A LibreQR instance is available at <https://qr.antopie.org>.
|
|||
|
||||
### Generic
|
||||
|
||||
Just place this source code in a Web server with PHP8.0+, extensions `gd`, `mbstring` and `iconv`, and writing rights on the `css/` directory.
|
||||
Place this source code in a Web server with PHP8.0+, extensions `gd`, `mbstring` and `iconv`, and writing rights on the `css/` directory. Every request needs to be sent to `index.php`.
|
||||
|
||||
#### Security hardening
|
||||
|
||||
|
|
|
|||
52
common.php
Normal file
52
common.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<div id="sideParams">
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="redundancy"><?= getIntlString('label_redundancy') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_redundancy') ?>
|
||||
</p>
|
||||
</details>
|
||||
<select id="redundancy" name="main[redundancy]">
|
||||
<option <?php if ($_POST['main']['redundancy'] === "low") echo 'selected="" '; ?>value="low">L - 7%</option>
|
||||
<option <?php if ($_POST['main']['redundancy'] === "medium") echo 'selected="" '; ?>value="medium">M - 15%</option>
|
||||
<option <?php if ($_POST['main']['redundancy'] === "quartile") echo 'selected="" '; ?>value="quartile">Q - 25%</option>
|
||||
<option <?php if ($_POST['main']['redundancy'] === "high") echo 'selected="" '; ?>value="high">H - 30%</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="margin"><?= getIntlString('label_margin') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_margin') ?>
|
||||
</p>
|
||||
</details>
|
||||
<input type="number" id="margin" placeholder="<?= DEFAULT_MARGIN ?>" name="main[margin]" required="" min="0" max="1024" value="<?= htmlspecialchars($_POST['main']['margin']) ?>">
|
||||
</div>
|
||||
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="size"><?= getIntlString('label_size') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_size') ?>
|
||||
</p>
|
||||
</details>
|
||||
<input type="number" id="size" placeholder="<?= DEFAULT_SIZE ?>" name="main[size]" required="" min="21" max="4096" value="<?= htmlspecialchars($_POST['main']['size']) ?>">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="colors">
|
||||
<div class="param">
|
||||
<label for="bgColor"><?= getIntlString('label_bgColor') ?></label>
|
||||
<input type="color" name="main[bgColor]" id="bgColor" value="<?= htmlspecialchars($_POST['main']['bgColor']) ?>">
|
||||
</div>
|
||||
<div class="param">
|
||||
<label for="fgColor"><?= getIntlString('label_fgColor') ?></label>
|
||||
<input type="color" name="main[fgColor]" id="fgColor" value="<?= htmlspecialchars($_POST['main']['fgColor']) ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="centered">
|
||||
<input class="button" type="submit" value="<?= getIntlString('button_create', raw: true) ?>" />
|
||||
</div>
|
||||
298
index.php
298
index.php
|
|
@ -61,109 +61,134 @@ function getIntlString(
|
|||
return "<span lang=\"en\">" . $template_loc[$string_label] . "</span>";
|
||||
}
|
||||
|
||||
$params = array(
|
||||
"txt" => "",
|
||||
"redundancy" => DEFAULT_REDUNDANCY,
|
||||
"margin" => DEFAULT_MARGIN,
|
||||
"size" => DEFAULT_SIZE,
|
||||
"bgColor" => DEFAULT_BGCOLOR,
|
||||
"fgColor" => DEFAULT_FGCOLOR,
|
||||
require "themes/" . THEME . "/theme.php";
|
||||
$colorScheme['theme'] = THEME;
|
||||
|
||||
$css_filename = Less_Cache::Get(
|
||||
less_files: ['style.less' => ''],
|
||||
parser_options: ['cache_dir' => 'css/', 'compress' => true],
|
||||
modify_vars: $colorScheme,
|
||||
);
|
||||
|
||||
preg_match('#.*/(?<page>.*)$#', $_SERVER['REQUEST_URI'], $matches);
|
||||
define('PAGE', match ($matches['page']) {
|
||||
'wifi' => 'wifi',
|
||||
'' => 'home',
|
||||
default => 'unknown',
|
||||
});
|
||||
|
||||
if (PAGE === 'unknown') {
|
||||
$allowed_filenames['css/' . $css_filename] = 'text/css';
|
||||
foreach ($themeDimensionsIcons as $icon_dimension)
|
||||
$allowed_filenames['themes/' . THEME . '/icons/' . $icon_dimension . '.png'] = 'image/png';
|
||||
foreach ($allowed_filenames as $filename => $type) {
|
||||
if (str_ends_with($_SERVER['REQUEST_URI'], $filename)) {
|
||||
header('Content-Type: ' . $type);
|
||||
echo file_get_contents($filename);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
http_response_code(404);
|
||||
}
|
||||
|
||||
$_POST = [
|
||||
"form" => $_POST['form'] ?? NULL,
|
||||
"wifi" => [
|
||||
"ssid" => $_POST['wifi']['ssid'] ?? "",
|
||||
"password" => $_POST['wifi']['password'] ?? "",
|
||||
],
|
||||
"main" => [
|
||||
"txt" => $_POST['main']['txt'] ?? "",
|
||||
"redundancy" => $_POST['main']['redundancy'] ?? DEFAULT_REDUNDANCY,
|
||||
"margin" => $_POST['main']['margin'] ?? DEFAULT_MARGIN,
|
||||
"size" => $_POST['main']['size'] ?? DEFAULT_SIZE,
|
||||
"bgColor" => $_POST['main']['bgColor'] ?? "#" . DEFAULT_BGCOLOR,
|
||||
"fgColor" => $_POST['main']['fgColor'] ?? "#" . DEFAULT_FGCOLOR,
|
||||
],
|
||||
];
|
||||
|
||||
if ($_POST['wifi']['ssid'] !== "") {
|
||||
if (!(strlen($_POST['wifi']['ssid']) >= 1 AND strlen($_POST['wifi']['ssid']) <= 4096)) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for ssid");
|
||||
}
|
||||
$escaped_ssid = preg_replace("/([\\\;\,\"\:])/", "\\\\$1", $_POST['wifi']['ssid']);
|
||||
|
||||
if ($_POST['wifi']['password'] === "")
|
||||
$_POST['main']['txt'] = "WIFI:T:nopass;S:{$escaped_ssid};;";
|
||||
else {
|
||||
if (strlen($_POST['wifi']['password']) > 4096) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for password");
|
||||
}
|
||||
|
||||
$escaped_password = preg_replace("/([\\\;\,\"\:])/", "\\\\$1", $_POST['wifi']['password']);
|
||||
|
||||
$_POST['main']['txt'] = "WIFI:T:WPA;S:{$escaped_ssid};P:{$escaped_password};;";
|
||||
}
|
||||
}
|
||||
|
||||
$qrCodeAvailable = NULL;
|
||||
|
||||
if (
|
||||
isset($_POST['txt'])
|
||||
AND isset($_POST['redundancy'])
|
||||
AND isset($_POST['margin'])
|
||||
AND isset($_POST['size'])
|
||||
AND isset($_POST['bgColor'])
|
||||
AND isset($_POST['fgColor'])
|
||||
) {
|
||||
|
||||
if ($_POST['main']['txt'] !== "") {
|
||||
$qrCodeAvailable = true;
|
||||
|
||||
if (strlen($_POST['txt']) >= 1 AND strlen($_POST['txt']) <= 4096) {
|
||||
$params['txt'] = $_POST['txt'];
|
||||
} else {
|
||||
if (!(strlen($_POST['main']['txt']) >= 1 AND strlen($_POST['main']['txt']) <= 4096)) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for txt");
|
||||
}
|
||||
|
||||
if ($_POST['redundancy'] === "low" OR $_POST['redundancy'] === "medium" OR $_POST['redundancy'] === "quartile" OR $_POST['redundancy'] === "high") {
|
||||
$params['redundancy'] = $_POST['redundancy'];
|
||||
} else {
|
||||
if (!in_array($_POST['main']['redundancy'], ["low", "medium", "quartile", "high"], strict: true)) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for redundancy");
|
||||
}
|
||||
|
||||
if (is_numeric($_POST['margin']) AND $_POST['margin'] >= 0 AND $_POST['margin'] <= 1024) {
|
||||
$params['margin'] = $_POST['margin'];
|
||||
} else if (empty($_POST['margin'])) {
|
||||
$params['margin'] = NULL;
|
||||
} else {
|
||||
if (!(is_numeric($_POST['main']['margin']) AND $_POST['main']['margin'] >= 0 AND $_POST['main']['margin'] <= 1024)) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for margin");
|
||||
}
|
||||
|
||||
if (is_numeric($_POST['size']) AND $_POST['size'] >= 21 AND $_POST['size'] <= 4096) {
|
||||
$params['size'] = $_POST['size'];
|
||||
} else if (empty($_POST['size'])) {
|
||||
$params['size'] = NULL;
|
||||
} else {
|
||||
if (!(is_numeric($_POST['main']['size']) AND $_POST['main']['size'] >= 21 AND $_POST['main']['size'] <= 4096)) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for size");
|
||||
}
|
||||
|
||||
if (preg_match("/^#[abcdefABCDEF0-9]{6}$/", $_POST['bgColor'])) {
|
||||
$params['bgColor'] = substr($_POST['bgColor'], -6);
|
||||
} else {
|
||||
if (preg_match("/^#[abcdefABCDEF0-9]{6}$/", $_POST['main']['bgColor']) === false) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for bgColor");
|
||||
}
|
||||
|
||||
if (preg_match("/^#[abcdefABCDEF0-9]{6}$/", $_POST['fgColor'])) {
|
||||
$params['fgColor'] = substr($_POST['fgColor'], -6);
|
||||
} else {
|
||||
if (preg_match("/^#[abcdefABCDEF0-9]{6}$/", $_POST['main']['fgColor']) === false) {
|
||||
http_response_code(400);
|
||||
exit("Wrong value for fgColor");
|
||||
}
|
||||
|
||||
$validFormSubmitted = true;
|
||||
|
||||
$rgbBgColor = array(
|
||||
'r' => hexdec(substr($params['bgColor'],0,2)),
|
||||
'g' => hexdec(substr($params['bgColor'],2,2)),
|
||||
'b' => hexdec(substr($params['bgColor'],4,2)),
|
||||
);
|
||||
$rgbBgColor = [
|
||||
'r' => hexdec(substr($_POST['main']['bgColor'],1,2)),
|
||||
'g' => hexdec(substr($_POST['main']['bgColor'],3,2)),
|
||||
'b' => hexdec(substr($_POST['main']['bgColor'],5,2)),
|
||||
];
|
||||
|
||||
$qrCode = Builder::create()
|
||||
->data($params['txt']);
|
||||
if (!is_null($params['margin']))
|
||||
$qrCode->margin($params['margin']);
|
||||
if (!is_null($params['size']))
|
||||
$qrCode->size($params['size']);
|
||||
|
||||
if ($params['redundancy'] === "high")
|
||||
$qrCode->errorCorrectionLevel(new ErrorCorrectionLevelHigh());
|
||||
else if ($params['redundancy'] === "quartile")
|
||||
$qrCode->errorCorrectionLevel(new ErrorCorrectionLevelQuartile());
|
||||
else if ($params['redundancy'] === "medium")
|
||||
$qrCode->errorCorrectionLevel(new ErrorCorrectionLevelMedium());
|
||||
else if ($params['redundancy'] === "low")
|
||||
$qrCode->errorCorrectionLevel(new ErrorCorrectionLevelLow());
|
||||
|
||||
$qrCode
|
||||
->backgroundColor(new Color(
|
||||
$rgbBgColor['r'],
|
||||
$rgbBgColor['g'],
|
||||
$rgbBgColor['b']
|
||||
))
|
||||
->foregroundColor(new Color(
|
||||
hexdec(substr($params['fgColor'],0,2)),
|
||||
hexdec(substr($params['fgColor'],2,2)),
|
||||
hexdec(substr($params['fgColor'],4,2))
|
||||
));
|
||||
->data($_POST['main']['txt'])
|
||||
->margin($_POST['main']['margin'])
|
||||
->size($_POST['main']['size'])
|
||||
->errorCorrectionLevel(match ($_POST['main']['redundancy']) {
|
||||
"low" => new ErrorCorrectionLevelLow(),
|
||||
"medium" => new ErrorCorrectionLevelMedium(),
|
||||
"quartile" => new ErrorCorrectionLevelQuartile(),
|
||||
"high" => new ErrorCorrectionLevelHigh(),
|
||||
})
|
||||
->backgroundColor(new Color(
|
||||
$rgbBgColor['r'],
|
||||
$rgbBgColor['g'],
|
||||
$rgbBgColor['b'],
|
||||
))
|
||||
->foregroundColor(new Color(
|
||||
hexdec(substr($_POST['main']['fgColor'],1,2)),
|
||||
hexdec(substr($_POST['main']['fgColor'],3,2)),
|
||||
hexdec(substr($_POST['main']['fgColor'],5,2)),
|
||||
));
|
||||
|
||||
try {
|
||||
$result = $qrCode->build();
|
||||
|
|
@ -179,21 +204,21 @@ if (
|
|||
<html lang="<?= $locale ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>LibreQR · <?= getIntlString('subtitle') ?></title>
|
||||
<title><?=
|
||||
match (PAGE) {
|
||||
'home' => 'LibreQR · ' . getIntlString('subtitle'),
|
||||
'wifi' => getIntlString('tab_wifi_title') . ' · LibreQR',
|
||||
'unknown' => getIntlString('error_404') . ' · LibreQR',
|
||||
}
|
||||
?></title>
|
||||
<meta name="description" content="<?= getIntlString('description', raw: true) ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<meta name="application-name" content="LibreQR">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' data:; style-src 'self'; form-action 'self';">
|
||||
<?php
|
||||
require "themes/" . THEME . "/theme.php";
|
||||
$colorScheme['theme'] = THEME;
|
||||
|
||||
$options = array('cache_dir' => 'css/', 'compress' => true);
|
||||
$cssFileName = Less_Cache::Get(array("style.less" => ""), $options, $colorScheme);
|
||||
?>
|
||||
<link rel="stylesheet" media="screen" href="css/<?= $cssFileName ?>">
|
||||
<link rel="stylesheet" media="screen" href="css/<?= $css_filename ?>">
|
||||
<?php
|
||||
foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
|
||||
echo ' <link rel="icon" type="image/png" href="themes/' . THEME . '/icons/' . $dimFav . '.png" sizes="' . $dimFav . 'x' . $dimFav . '">' . "\n";
|
||||
|
|
@ -204,97 +229,73 @@ foreach($themeDimensionsIcons as $dimFav) // Set all icons dimensions
|
|||
|
||||
<header>
|
||||
<a id="linkTitles" href="./">
|
||||
<div id="titles">
|
||||
<hgroup id="titles">
|
||||
<h1>LibreQR</h1>
|
||||
<h2><?= getIntlString('subtitle') ?></h2>
|
||||
</div>
|
||||
<p><?= getIntlString('subtitle') ?></p>
|
||||
</hgroup>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<form method="post" action="./#output">
|
||||
<nav>
|
||||
<h2 class="sr-only">Type de code QR</h2>
|
||||
<ul>
|
||||
<li<?php if (PAGE == 'home') echo ' class="tab-selected"' ?>><a href="./"><div><?= getIntlString('tab_text') ?></div></a></li>
|
||||
<li<?php if (PAGE == 'wifi') echo ' class="tab-selected"' ?>><a href="./wifi"><div><?= getIntlString('tab_wifi') ?></div></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div class="param" id="txtParam">
|
||||
<?php if (PAGE === 'wifi') { ?>
|
||||
<form method="post" action="./wifi#output">
|
||||
<div class="param textboxParam">
|
||||
<label for="ssid"><?= getIntlString('label_wifi_ssid') ?></label>
|
||||
<input type="text" id="ssid" placeholder="<?= getIntlString('placeholder_wifi_ssid', raw: true) ?>" name="wifi[ssid]" required maxlength="4096" value="<?= htmlspecialchars($_POST['wifi']['ssid']) ?>">
|
||||
</div>
|
||||
<div class="param textboxParam">
|
||||
<details>
|
||||
<summary><label for="password"><?= getIntlString('label_wifi_password') ?></label></summary>
|
||||
<div class="helpText">
|
||||
<?= getIntlString('help_wifi_password') ?>
|
||||
</div>
|
||||
</details>
|
||||
<input type="text" id="password" placeholder="<?= getIntlString('placeholder_wifi_password', raw: true) ?>" name="wifi[password]" maxlength="4096" value="<?= htmlspecialchars($_POST['wifi']['password']) ?>">
|
||||
</div>
|
||||
<?php require 'common.php' ?>
|
||||
</form>
|
||||
<?php } else if (PAGE === 'home') { ?>
|
||||
<form method="post" action="./#output">
|
||||
<div class="param textboxParam" id="txtParam">
|
||||
<details>
|
||||
<summary><label for="txt"><?= getIntlString('label_content') ?></label></summary>
|
||||
<div class="helpText">
|
||||
<?= getIntlString('help_content') ?>
|
||||
</div>
|
||||
</details>
|
||||
<textarea rows="3" required="" id="txt" placeholder="<?= getIntlString('placeholder', raw: true) ?>" name="txt"><?= htmlspecialchars($params['txt']) ?></textarea>
|
||||
<textarea rows="3" id="txt" placeholder="<?= getIntlString('placeholder', raw: true) ?>" name="main[txt]"><?= htmlspecialchars($_POST['main']['txt']) ?></textarea>
|
||||
</div>
|
||||
|
||||
<div id="sideParams">
|
||||
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="redundancy"><?= getIntlString('label_redundancy') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_redundancy') ?>
|
||||
</p>
|
||||
</details>
|
||||
<select id="redundancy" name="redundancy">
|
||||
<option <?php if ($params['redundancy'] === "low") echo 'selected="" '; ?>value="low">L - 7%</option>
|
||||
<option <?php if ($params['redundancy'] === "medium") echo 'selected="" '; ?>value="medium">M - 15%</option>
|
||||
<option <?php if ($params['redundancy'] === "quartile") echo 'selected="" '; ?>value="quartile">Q - 25%</option>
|
||||
<option <?php if ($params['redundancy'] === "high") echo 'selected="" '; ?>value="high">H - 30%</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="margin"><?= getIntlString('label_margin') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_margin') ?>
|
||||
</p>
|
||||
</details>
|
||||
<input type="number" id="margin" placeholder="<?= DEFAULT_MARGIN ?>" name="margin" required="" min="0" max="1024" value="<?= htmlspecialchars($params['margin']) ?>">
|
||||
</div>
|
||||
|
||||
<div class="param">
|
||||
<details>
|
||||
<summary><label for="size"><?= getIntlString('label_size') ?></label></summary>
|
||||
<p class="helpText">
|
||||
<?= getIntlString('help_size') ?>
|
||||
</p>
|
||||
</details>
|
||||
<input type="number" id="size" placeholder="<?= DEFAULT_SIZE ?>" name="size" required="" min="21" max="4096" value="<?= htmlspecialchars($params['size']) ?>">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="colors">
|
||||
<div class="param">
|
||||
<label for="bgColor"><?= getIntlString('label_bgColor') ?></label>
|
||||
<input type="color" name="bgColor" id="bgColor" value="#<?= htmlspecialchars($params['bgColor']) ?>">
|
||||
</div>
|
||||
<div class="param">
|
||||
<label for="fgColor"><?= getIntlString('label_fgColor') ?></label>
|
||||
<input type="color" name="fgColor" id="fgColor" value="#<?= htmlspecialchars($params['fgColor']) ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="centered">
|
||||
<input class="button" type="submit" value="<?= getIntlString('button_create', raw: true) ?>" />
|
||||
</div>
|
||||
|
||||
<?php require 'common.php' ?>
|
||||
</form>
|
||||
<?php } else { ?>
|
||||
<p>
|
||||
<?= getIntlString('error_404') ?>
|
||||
</p>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
|
||||
if ($qrCodeAvailable) {
|
||||
$dataUri = $result->getDataUri();
|
||||
|
||||
$qrSize = $params['size'] + 2 * $params['margin'];
|
||||
$qrSize = $_POST['main']['size'] + 2 * $_POST['main']['margin'];
|
||||
|
||||
?>
|
||||
|
||||
<section id="output">
|
||||
<div class="centered" id="downloadQR">
|
||||
<a href="<?= $dataUri ?>" class="button" download="<?= htmlspecialchars($params['txt']); ?>.png"><?= getIntlString('button_download') ?></a>
|
||||
<a href="<?= $dataUri ?>" class="button" download="<?= htmlspecialchars($_POST['main']['txt']); ?>.png"><?= getIntlString('button_download') ?></a>
|
||||
</div>
|
||||
|
||||
<div class="centered" id="showOnlyQR">
|
||||
<a title="<?= getIntlString('title_showOnlyQR', raw: true) ?>" href="<?= $dataUri ?>"><img width="<?= $qrSize ?>" height="<?= $qrSize ?>" alt='<?= getIntlString('alt_QR_before', raw: true) ?><?= htmlspecialchars($params['txt']); ?><?= getIntlString('alt_QR_after', raw: true) ?>' id="qrCode"<?php
|
||||
<a title="<?= getIntlString('title_showOnlyQR', raw: true) ?>" href="<?= $dataUri ?>"><img width="<?= $qrSize ?>" height="<?= $qrSize ?>" alt='<?= getIntlString('alt_QR_before', raw: true) ?><?= htmlspecialchars($_POST['main']['txt']); ?><?= getIntlString('alt_QR_after', raw: true) ?>' id="qrCode"<?php
|
||||
|
||||
// Compute the difference between the QR code and theme background colors
|
||||
$diffLight = abs($rgbBgColor['r']-hexdec(substr($colorScheme['bg-light'],-6,2))) + abs($rgbBgColor['g']-hexdec(substr($colorScheme['bg-light'],-4,2))) + abs($rgbBgColor['b']-hexdec(substr($colorScheme['bg-light'],-2,2)));
|
||||
|
|
@ -308,6 +309,17 @@ if ($qrCodeAvailable) {
|
|||
echo " class='needDarkContrast'";
|
||||
?> src="<?= $dataUri ?>"></a>
|
||||
</div>
|
||||
<?php if (PAGE === "wifi") { ?>
|
||||
<p>
|
||||
<?= getIntlString('wifi_raw_content_before') ?><code><?= htmlspecialchars($_POST['main']['txt']) ?></code><?= getIntlString('wifi_raw_content_after') ?>
|
||||
</p>
|
||||
<form method="POST" action="./">
|
||||
<?php foreach ($_POST['main'] as $name => $value) { ?>
|
||||
<input type="hidden" name="main[<?= htmlspecialchars($name) ?>]" value="<?= htmlspecialchars($value) ?>" />
|
||||
<?php } ?>
|
||||
<input type="submit" value="<?= getIntlString('button_edit') ?>" />
|
||||
</form>
|
||||
<?php } ?>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ $loc = array(
|
|||
'subtitle' => "QR codes generator",
|
||||
'description' => "Generate QR codes freely. Choose content, size, colors…",
|
||||
|
||||
'tab_text' => "Text",
|
||||
'tab_wifi' => "Wifi",
|
||||
'tab_wifi_title' => "Wifi QR codes generation",
|
||||
|
||||
'label_wifi_ssid' => "Network name / SSID",
|
||||
'label_wifi_password' => "Password",
|
||||
'label_content' => "Text to encode",
|
||||
'label_redundancy' => "Redundancy rate",
|
||||
'label_margin' => "Margin size",
|
||||
|
|
@ -11,7 +17,10 @@ $loc = array(
|
|||
'label_fgColor' => "Foreground color",
|
||||
|
||||
'placeholder' => "Enter the text to encode in the QR code",
|
||||
'placeholder_wifi_ssid' => "Box-A31B",
|
||||
'placeholder_wifi_password' => "correct horse battery staple",
|
||||
|
||||
'help_wifi_password' => "The WPA, WPA2 or WPA3 key. Leave empty if it's an open network.",
|
||||
'help_content' => "
|
||||
<p>You can encode whatever text you want.</p>
|
||||
<p>Software decoding these QR codes could suggest to open them with dedicated software, depending on their <a href='https://en.wikipedia.org/wiki/List_of_URI_schemes' hreflang='en' rel='help external noreferrer'>URI scheme</a>.</p>
|
||||
|
|
@ -25,12 +34,16 @@ $loc = array(
|
|||
|
||||
'button_create' => "Generate",
|
||||
'button_download' => "Save this QR code",
|
||||
'button_edit' => "Edit",
|
||||
|
||||
'title_showOnlyQR' => "Show this QR code only",
|
||||
|
||||
'alt_QR_before' => 'QR code meaning "',
|
||||
'alt_QR_after' => '"',
|
||||
|
||||
'wifi_raw_content_before' => "This QR code contains: ",
|
||||
'wifi_raw_content_after' => "",
|
||||
|
||||
'metaText_qr' => "
|
||||
<h3>What's a QR code?</h3>
|
||||
A QR code is a 2 dimensional barcode in which text is written in binary. It can be decoded with a device equipped with a photo sensor and adequate software.
|
||||
|
|
@ -39,4 +52,5 @@ $loc = array(
|
|||
'metaText_legal' => "LibreQR " . LIBREQR_VERSION . " is free software whose <a href='https://code.antopie.org/miraty/libreqr/' rel='external noreferrer'>source code</a> is available under the terms of the <abbr title='GNU Affero General Public License version 3 or any later version'><a href='LICENSE.html' hreflang='en' rel='license'>AGPLv3</a>+</abbr>.",
|
||||
|
||||
'error_generation' => "An error occurred while generating the QR code. Try with different parameters.",
|
||||
'error_404' => "This page doesn't exist.",
|
||||
);
|
||||
|
|
@ -3,6 +3,12 @@ $loc = array(
|
|||
'subtitle' => "Générer des codes QR",
|
||||
'description' => "Générer des codes QR librement. Choix du contenu, de la taille, des couleurs…",
|
||||
|
||||
'tab_text' => "Texte",
|
||||
'tab_wifi' => "Wifi",
|
||||
'tab_wifi_title' => "Générer des codes QR Wifi",
|
||||
|
||||
'label_wifi_ssid' => "Nom du réseau / SSID",
|
||||
'label_wifi_password' => "Mot de passe",
|
||||
'label_content' => "Texte à encoder",
|
||||
'label_redundancy' => "Taux de redondance",
|
||||
'label_margin' => "Taille de la marge",
|
||||
|
|
@ -11,7 +17,10 @@ $loc = array(
|
|||
'label_fgColor' => "Couleur de premier plan",
|
||||
|
||||
'placeholder' => "Entrez le texte à encoder dans le code QR",
|
||||
'placeholder_wifi_ssid' => "Box-A31B",
|
||||
'placeholder_wifi_password' => "correct cheval batterie agrafe",
|
||||
|
||||
'help_wifi_password' => "La clé WPA, WPA2 ou WPA3. Laisser vide si c'est un réseau ouvert.",
|
||||
'help_content' => "
|
||||
<p>Vous pouvez encoder ce que vous voulez sous forme de texte.</p>
|
||||
<p>Les logiciels qui décodent ces codes QR pourraient proposer de les ouvrir avec un logiciel dédié, en fonction de leur <a href='https://fr.wikipedia.org/wiki/Sch%C3%A9ma_d%27URI' hreflang='fr' rel='help external noreferrer'>schéma d'URI</a>.</p>
|
||||
|
|
@ -25,12 +34,16 @@ $loc = array(
|
|||
|
||||
'button_create' => "Générer",
|
||||
'button_download' => "Enregistrer ce code QR",
|
||||
'button_edit' => "Modifier",
|
||||
|
||||
'title_showOnlyQR' => "Afficher uniquement ce code QR",
|
||||
|
||||
'alt_QR_before' => "Code QR signifiant « ",
|
||||
'alt_QR_after' => " »",
|
||||
|
||||
'wifi_raw_content_before' => "Ce code QR contient : ",
|
||||
'wifi_raw_content_after' => "",
|
||||
|
||||
'metaText_qr' => "
|
||||
<h3>Qu'est-ce qu'un code QR ?</h3>
|
||||
Un code QR est un code-barres en 2 dimensions dans lequel du texte est inscrit en binaire. Il peut être décodé avec un appareil muni d'un capteur photo et d'un logiciel adéquat.
|
||||
|
|
@ -39,4 +52,5 @@ $loc = array(
|
|||
'metaText_legal' => "LibreQR " . LIBREQR_VERSION . " est un logiciel libre dont le <a href='https://code.antopie.org/miraty/libreqr/' rel='external noreferrer'>code source</a> est disponible selon les termes de l'<abbr title='GNU Affero General Public License version 3 ou toute version ultérieure'><a href='LICENSE.html' hreflang='en' rel='license'>AGPLv3</a>+</abbr>.",
|
||||
|
||||
'error_generation' => "Une erreur a eu lieu lors de la génération du code QR. Essayez avec des paramètres différents.",
|
||||
'error_404' => "Cette page n'existe pas.",
|
||||
);
|
||||
|
|
@ -3,6 +3,12 @@ $loc = array(
|
|||
'subtitle' => "subtitle",
|
||||
'description' => "description",
|
||||
|
||||
'tab_text' => "tab_text",
|
||||
'tab_wifi' => "tab_wifi",
|
||||
'tab_wifi_title' => "tab_wifi_title",
|
||||
|
||||
'label_wifi_ssid' => "label_wifi_ssid",
|
||||
'label_wifi_password' => "label_wifi_password",
|
||||
'label_content' => "label_content",
|
||||
'label_redundancy' => "label_redundancy",
|
||||
'label_margin' => "label_margin",
|
||||
|
|
@ -11,9 +17,10 @@ $loc = array(
|
|||
'label_fgColor' => "label_fgColor",
|
||||
|
||||
'placeholder' => "placeholder",
|
||||
'placeholder_wifi_ssid' => "placeholder_wifi_ssid",
|
||||
'placeholder_wifi_password' => "placeholder_wifi_password",
|
||||
|
||||
'value_default' => "value_default",
|
||||
|
||||
'help_wifi_password' => "help_wifi_password",
|
||||
'help_content' => "help_content",
|
||||
'help_redundancy' => "help_redundancy",
|
||||
'help_margin' => "help_margin",
|
||||
|
|
@ -21,14 +28,19 @@ $loc = array(
|
|||
|
||||
'button_create' => "button_create",
|
||||
'button_download' => "button_download",
|
||||
'button_edit' => "button_edit",
|
||||
|
||||
'title_showOnlyQR' => "title_showOnlyQR",
|
||||
|
||||
'alt_QR_before' => "alt_QR_before",
|
||||
'alt_QR_after' => "alt_QR_after",
|
||||
|
||||
'wifi_raw_content_before' => "wifi_raw_content_before",
|
||||
'wifi_raw_content_after' => "wifi_raw_content_after",
|
||||
|
||||
'metaText_qr' => "metaText_qr",
|
||||
'metaText_legal' => "metaText_legal",
|
||||
|
||||
'error_generation' => "error_generation",
|
||||
'error_404' => "error_404",
|
||||
);
|
||||
105
style.less
105
style.less
|
|
@ -72,8 +72,90 @@ a {
|
|||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
& ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
& li {
|
||||
& div {
|
||||
padding: 8px 25px 8px 25px;
|
||||
}
|
||||
|
||||
&.tab-selected {
|
||||
border: solid;
|
||||
border-width: 2px 2px 0px 2px;
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
@media @light {
|
||||
background-color: @bg-light;
|
||||
}
|
||||
@media @dark {
|
||||
background-color: @bg-dark;
|
||||
}
|
||||
}
|
||||
&:not(&.tab-selected) {
|
||||
border-bottom: 2px solid;
|
||||
@media @light {
|
||||
border-top: 2px solid @bg-light;
|
||||
}
|
||||
@media @dark {
|
||||
border-top: 2px solid @bg-dark;
|
||||
}
|
||||
&:first-child {
|
||||
@media @light {
|
||||
border-left: 2px solid @bg-light;
|
||||
}
|
||||
@media @dark {
|
||||
border-left: 2px solid @bg-dark;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
@media @light {
|
||||
border-right: 2px solid @bg-light;
|
||||
}
|
||||
@media @dark {
|
||||
border-right: 2px solid @bg-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media @light {
|
||||
border-color: @border-light;
|
||||
}
|
||||
@media @dark {
|
||||
border-color: @border-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label[for=ssid] {
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.sr-only { /* Hide content from screen but not from screen readers */
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
|
|
@ -163,6 +245,15 @@ summary {
|
|||
}
|
||||
}
|
||||
|
||||
#output form, #output input[type=submit], #output p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#output input[type=submit] {
|
||||
font-size: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -193,6 +284,10 @@ header {
|
|||
}
|
||||
}
|
||||
|
||||
hgroup p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#titles {
|
||||
margin-left: 2%;
|
||||
}
|
||||
|
|
@ -312,7 +407,7 @@ small {
|
|||
|
||||
/* Inputs */
|
||||
|
||||
#redundancy, #margin, #txt, #size, input[type=color], input[type=submit], .button {
|
||||
#redundancy, #margin, #ssid, #password, #txt, #size, input[type=color], input[type=submit], .button {
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-radius: 10px;
|
||||
|
|
@ -364,6 +459,10 @@ small {
|
|||
}
|
||||
}
|
||||
|
||||
#password, #ssid {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
#redundancy {
|
||||
width: 250px;
|
||||
height: 44px;
|
||||
|
|
@ -407,7 +506,7 @@ input[type=color] {
|
|||
}
|
||||
}
|
||||
|
||||
#txtParam {
|
||||
.textboxParam {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
@ -438,7 +537,7 @@ input[type=submit] {
|
|||
padding-right: 14px;
|
||||
}
|
||||
|
||||
#txt::placeholder {
|
||||
#password::placeholder, #ssid::placeholder, #txt::placeholder {
|
||||
opacity: 1;
|
||||
font-family: system-ui, sans-serif;
|
||||
font-weight: normal;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue