Fix owner-scope query bug returning the wrong qr code by id
qr_apply_owner_scope() used where('id_owner', X) + orWhere('id_owner', NULL,
'IS'). Any caller that had already added its own where('id', $id) before
calling it (qrcode_image.php, bulk_action.php's download path) ended up
with "WHERE id = ? AND id_owner = ? OR id_owner IS NULL" - AND binds
tighter than OR in SQL, so this was actually "(id = ? AND id_owner = ?) OR
(id_owner IS NULL)", which silently detaches the id filter and returns an
arbitrary null-owner row instead (or nothing, if that row's file is
missing) whenever the intended row didn't have a null owner. This is what
broke qr code thumbnails/downloads on qr.ensembia.com for scoped (non-super)
accounts, old and newly-created codes alike - reproduced and confirmed
fixed with a local before/after query dump, then with a live HTTP request
scenario (two accounts, two codes, one null-owner).
Fixed by building the scope as a single parenthesized raw condition
instead of two separate where() calls, so it can't be split apart by
whatever the caller already added to the query.
Also this session, per user feedback on the OSS rebrand review:
- Format moved back next to Filename in both qr-creation forms (was
separated from it when Filename got grouped with Owner last session).
- README/About now mention the temporary admin/admin demo account instead
of the not-yet-built self-registration flow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fo3DiRRpmz2DXjD7Uzhc8u
This commit is contained in:
@@ -8,7 +8,8 @@ of the original [PHP Dynamic Qr code](https://github.com/giandonatoinverso/PHP-D
|
|||||||
project by Giandonato Inverso, built on [AdminLTE](https://adminlte.io/).
|
project by Giandonato Inverso, built on [AdminLTE](https://adminlte.io/).
|
||||||
|
|
||||||
- **Try it free:** [qr.ensembia.com](https://qr.ensembia.com) - fully functional OSS test
|
- **Try it free:** [qr.ensembia.com](https://qr.ensembia.com) - fully functional OSS test
|
||||||
instance, register your own account any time.
|
instance. Self-service signup isn't live yet, so log in with the temporary shared demo
|
||||||
|
account `admin` / `admin` in the meantime.
|
||||||
- **Commercial VIP edition** (self-service create-rights, logo-embedded QR codes):
|
- **Commercial VIP edition** (self-service create-rights, logo-embedded QR codes):
|
||||||
[www.qrforge.eu](https://www.qrforge.eu).
|
[www.qrforge.eu](https://www.qrforge.eu).
|
||||||
- **Self-host it yourself:** this repository, MIT-licensed.
|
- **Self-host it yourself:** this repository, MIT-licensed.
|
||||||
|
|||||||
+2
-1
@@ -51,7 +51,8 @@ require_once BASE_PATH . '/includes/auth_validate.php';
|
|||||||
This is the free, open-source (MIT) edition of QRForge. It runs unmodified
|
This is the free, open-source (MIT) edition of QRForge. It runs unmodified
|
||||||
as a live, fully functional try-out at
|
as a live, fully functional try-out at
|
||||||
<a href="https://qr.ensembia.com" target="_blank">qr.ensembia.com</a> -
|
<a href="https://qr.ensembia.com" target="_blank">qr.ensembia.com</a> -
|
||||||
register a free account there any time.
|
self-service signup isn't live yet, so log in with the temporary shared
|
||||||
|
demo account <code>admin</code> / <code>admin</code> in the meantime.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The commercial VIP edition (paid create-rights and logo-embedded QR codes)
|
The commercial VIP edition (paid create-rights and logo-embedded QR codes)
|
||||||
|
|||||||
@@ -118,18 +118,6 @@
|
|||||||
|
|
||||||
<div class="col-sm-12 mb-2">
|
<div class="col-sm-12 mb-2">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 col-md-1">
|
|
||||||
<label for="format">Format *</label>
|
|
||||||
<select name="format" class="form-control" required="required">
|
|
||||||
<option value="png" selected>PNG</option>
|
|
||||||
<option value="gif">GIF</option>
|
|
||||||
<option value="jpeg">JPEG</option>
|
|
||||||
<option value="jpg">JPG</option>
|
|
||||||
<option value="svg">SVG</option>
|
|
||||||
<option value="eps">EPS</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="frame_text">Frame text</label>
|
<label for="frame_text">Frame text</label>
|
||||||
@@ -178,6 +166,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6 col-md-1">
|
||||||
|
<label for="format">Format *</label>
|
||||||
|
<select name="format" class="form-control" required="required">
|
||||||
|
<option value="png" selected>PNG</option>
|
||||||
|
<option value="gif">GIF</option>
|
||||||
|
<option value="jpeg">JPEG</option>
|
||||||
|
<option value="jpg">JPG</option>
|
||||||
|
<option value="svg">SVG</option>
|
||||||
|
<option value="eps">EPS</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ($_SESSION['type'] === 'super') { ?>
|
<?php if ($_SESSION['type'] === 'super') { ?>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@@ -114,23 +114,6 @@ if (QRCODE_GENERATOR === "internal-chillerlan.qrcode") {
|
|||||||
|
|
||||||
<div class="col-sm-12 mb-2">
|
<div class="col-sm-12 mb-2">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6 col-md-1">
|
|
||||||
<label for="format">Format</label>
|
|
||||||
<select name="format" class="form-control">
|
|
||||||
<option value="png">PNG</option>
|
|
||||||
<option value="gif">GIF</option>
|
|
||||||
<option value="jpeg">JPEG</option>
|
|
||||||
<option value="jpg">JPG</option>
|
|
||||||
<option value="svg">SVG</option>
|
|
||||||
<?php
|
|
||||||
if (QRCODE_GENERATOR === "internal-chillerlan.qrcode") {
|
|
||||||
echo ' <option value="svgbw">SVG (BW)</option>';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<option value="eps">EPS</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="frame_text">Frame text</label>
|
<label for="frame_text">Frame text</label>
|
||||||
@@ -179,6 +162,23 @@ if (QRCODE_GENERATOR === "internal-chillerlan.qrcode") {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6 col-md-1">
|
||||||
|
<label for="format">Format</label>
|
||||||
|
<select name="format" class="form-control">
|
||||||
|
<option value="png">PNG</option>
|
||||||
|
<option value="gif">GIF</option>
|
||||||
|
<option value="jpeg">JPEG</option>
|
||||||
|
<option value="jpg">JPG</option>
|
||||||
|
<option value="svg">SVG</option>
|
||||||
|
<?php
|
||||||
|
if (QRCODE_GENERATOR === "internal-chillerlan.qrcode") {
|
||||||
|
echo ' <option value="svgbw">SVG (BW)</option>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<option value="eps">EPS</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ($_SESSION['type'] === 'super') { ?>
|
<?php if ($_SESSION['type'] === 'super') { ?>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
@@ -177,12 +177,18 @@ function qr_has_full_visibility() {
|
|||||||
/**
|
/**
|
||||||
* Apply the current session's owner scope to a MysqliDb query builder in place.
|
* Apply the current session's owner scope to a MysqliDb query builder in place.
|
||||||
* No-op when the session has full visibility.
|
* No-op when the session has full visibility.
|
||||||
|
*
|
||||||
|
* Uses a single raw, parenthesized condition rather than where()+orWhere() -
|
||||||
|
* the previous two-call form produced "WHERE id = ? AND id_owner = ? OR id_owner
|
||||||
|
* IS NULL" whenever a caller had already added its own where('id', ...) (e.g.
|
||||||
|
* qrcode_image.php, bulk_action.php), and AND binds tighter than OR in SQL, so
|
||||||
|
* the OR silently detached from the id filter and matched *any* id_owner-NULL
|
||||||
|
* row instead of the one actually requested.
|
||||||
*/
|
*/
|
||||||
function qr_apply_owner_scope($db) {
|
function qr_apply_owner_scope($db) {
|
||||||
$scope_owner_id = qr_scope_owner_id();
|
$scope_owner_id = qr_scope_owner_id();
|
||||||
if ($scope_owner_id !== null) {
|
if ($scope_owner_id !== null) {
|
||||||
$db->where('id_owner', $scope_owner_id);
|
$db->where('(id_owner = ' . (int) $scope_owner_id . ' OR id_owner IS NULL)');
|
||||||
$db->orWhere('id_owner', NULL, 'IS');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user