Compare commits
182 Commits
9cdfbe7a10
..
v0.9
| Author | SHA1 | Date | |
|---|---|---|---|
| 43504d92dc | |||
| 402bda0fbf | |||
| b5bfd9a4d8 | |||
| def7b81a11 | |||
| 9645ce94e2 | |||
| 164872de4d | |||
| ad5a5df81e | |||
| 23e8d9b765 | |||
| a8f55506c8 | |||
| 89bf472867 | |||
| 7276744f32 | |||
| 23daf9c236 | |||
| c3c6f167e0 | |||
| 4e9fed755c | |||
| 6387d24846 | |||
| 52c9f65c61 | |||
| 3afe3b7698 | |||
| 8db3158239 | |||
| b3b799819e | |||
| f89b39bde3 | |||
| acb154502b | |||
| f24a7086ab | |||
| 2f0c879158 | |||
| 2ce6a03921 | |||
| 40ec07fbb1 | |||
| 6cfbc4a759 | |||
| 3ee79bfab7 | |||
| a2fdf79491 | |||
| 236d7342d3 | |||
| 1f3110b26e | |||
| 8b24fd839d | |||
| 011e91e3d0 | |||
| 737ceca97b | |||
| b4b42ddb29 | |||
| 3ca4163715 | |||
| c5f1b0d74f | |||
| d825f597b8 | |||
| 850f5e5c52 | |||
| c46dae55ce | |||
| 4d33cf5379 | |||
| a1bd583ad3 | |||
| 597afbb1fe | |||
| 5028541bfd | |||
| 6d42677732 | |||
| 1499f06c71 | |||
| 058277c0fc | |||
| a426d45be1 | |||
| 3f7ac0bce1 | |||
| 9548a6d73a | |||
| 2715f2106c | |||
| e43e8f774e | |||
| acebfdd708 | |||
| 005c67d721 | |||
| 9f2d14abf8 | |||
| eba0ebbba7 | |||
| 068ddebd35 | |||
| d0d3daf7db | |||
| 92eb66fb35 | |||
| b85f98e16d | |||
| a7953f05bb | |||
| 06ddd19378 | |||
| 2b6c802659 | |||
| 33651fcabb | |||
| b496e51ace | |||
| 1217e32856 | |||
| 6646cc9545 | |||
| 915ea383b7 | |||
| 93980efdb7 | |||
| b52a61ca40 | |||
| c9fa6abf06 | |||
| 15c84c0863 | |||
| 90a7b2890b | |||
| 03da2d0432 | |||
| 68a2b9f7f3 | |||
| 5335b6fb7e | |||
| fadde16882 | |||
| 575a6b3caa | |||
| cdab7df35d | |||
| 9a0a2c7928 | |||
| 995272fa8d | |||
| ef6410253c | |||
| f9ad48f65a | |||
| 4b28c09d49 | |||
| d14ec02e4e | |||
| c87a99a067 | |||
| eb3c275035 | |||
| e448066176 | |||
| abd55062f3 | |||
| e99e97cae2 | |||
| 6d1c3ac7c4 | |||
| e2d9aad91f | |||
| fa709c95db | |||
| 8cb8e36114 | |||
| c3225c6f3f | |||
| 9cf354910b | |||
| a18657994e | |||
| 4b5c9a800b | |||
| a85cee4fda | |||
| 327cadaddb | |||
| 4da9be3e3e | |||
| b26c905b2e | |||
| f458094e0d | |||
| b16f30b5a3 | |||
| f072f151fd | |||
| 38ddbe43c7 | |||
| 9799509ff6 | |||
| f0d43fd18b | |||
| 5e531f4e15 | |||
| a0944afd3c | |||
| 9b61284a1e | |||
| 70ec7afc90 | |||
| 1934c78251 | |||
| 8f053474e7 | |||
| b80636049f | |||
| a8e4cf18ff | |||
| 418215cd23 | |||
| 8bbb4354c0 | |||
| 2057df1924 | |||
| b457823654 | |||
| 02754fba37 | |||
| 25add5b7fd | |||
| 2aa867aa2a | |||
| 9cbf68a99e | |||
| dfaee77d86 | |||
| 59c6dc9233 | |||
| c3e04a4357 | |||
| 97da7f0d4f | |||
| 4dd7f9ab25 | |||
| 3000271d95 | |||
| 1194259e6e | |||
| 5f1534f0be | |||
| c76c1164fc | |||
| c8b3bba9f0 | |||
| 10091ac8e4 | |||
| a6bf0d6ca9 | |||
| 44e8465129 | |||
| cd00141252 | |||
| 0ca8bd7cb2 | |||
| 554a27762d | |||
| 36c52ba003 | |||
| 773d4960fd | |||
| 7757bcf76b | |||
| 76883de681 | |||
| 8d45a02149 | |||
| d3e11399f7 | |||
| 86f32b6327 | |||
| 97df13f3f0 | |||
| 4ac9cd811a | |||
| 1968201a48 | |||
| b39c88fc12 | |||
| 9118d4f33c | |||
| f8bc49c164 | |||
| 9db2388d51 | |||
| 03c9c2d720 | |||
| 3bb2545521 | |||
| 283df4b81c | |||
| e64ca74003 | |||
| 0c2988791f | |||
| e123385dac | |||
| 1c819e6626 | |||
| 8af83452ba | |||
| 527eb7b3ba | |||
| fe4c63e3a6 | |||
| 601be05d5c | |||
| f4f061d857 | |||
| f1eb8545b4 | |||
| 7e3cef7544 | |||
| 5530f62195 | |||
| df3211d583 | |||
| 117b2b21a2 | |||
| 5430504fa0 | |||
| 65c279b65d | |||
| ceda04f97e | |||
| 76cad846f9 | |||
| f0d187f8b7 | |||
| fefac0fa9f | |||
| 6f920aec63 | |||
| ab7a82edbf | |||
| 7e867ddf9d | |||
| 255201169f | |||
| ca0108c247 | |||
| 23864047ce |
@@ -4,7 +4,7 @@ TYPE=docker
|
|||||||
QRCODE_GENERATOR=internal-chillerlan.qrcode
|
QRCODE_GENERATOR=internal-chillerlan.qrcode
|
||||||
BASE_URL=http://localhost
|
BASE_URL=http://localhost
|
||||||
|
|
||||||
DATABASE_HOST=php-dynamic-qrcode-db
|
DATABASE_HOST=qrforge-db
|
||||||
DATABASE_PORT=3306
|
DATABASE_PORT=3306
|
||||||
DATABASE_NAME=qrcode
|
DATABASE_NAME=qrcode
|
||||||
DATABASE_USER=qrcode
|
DATABASE_USER=qrcode
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM nginx:1.27-alpine
|
||||||
|
|
||||||
|
# The php-dynamic-qrcode container builds the full app (incl. composer/vendor) into its
|
||||||
|
# own image at /var/www/html. nginx runs as a separate container and has no access to
|
||||||
|
# that filesystem, so it needs its own copy of just the static assets it serves directly
|
||||||
|
# via try_files - everything else (*.php) is proxied to php-fpm regardless. Without this,
|
||||||
|
# every static asset request (CSS/JS/manifest) falls through nginx's try_files to
|
||||||
|
# index.php, which requires a login and silently redirects there instead of serving the
|
||||||
|
# file.
|
||||||
|
COPY src/dist /var/www/html/dist
|
||||||
|
COPY src/plugins /var/www/html/plugins
|
||||||
|
COPY src/manifest.json /var/www/html/manifest.json
|
||||||
|
COPY src/service-worker.js /var/www/html/service-worker.js
|
||||||
|
COPY src/favicon.ico /var/www/html/favicon.ico
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Giandonato Inverso
|
Copyright (c) 2020 Giandonato Inverso
|
||||||
|
Copyright (c) 2026 Dillard Blom
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,65 +1,70 @@
|
|||||||
<p align="center"><img src="https://www.giandonatoinverso.it/qrcode/dist/img/DynamicQRCode_Original.png"></p>
|
<p align="center"><img src="src/dist/img/brand/logo.svg" alt="QRForge" width="320"></p>
|
||||||
|
|
||||||
**PHP Dynamic Qr code** is a script that allows the generation and saving of dynamic and static QR codes. It has a clean, responsive, and user-friendly design. It is based on [AdminLte](https://adminlte.io/), the "Best open source admin dashboard & control panel theme. Built on top of Bootstrap" and [Core PHP Admin Panel](https://github.com/chetans9/core-php-admin-panel), a simple Admin Panel written in core PHP that contains an implementation of general features you might need in your website admin panel like: record management (CRUD), secure authentication, pagination, filters.
|
<p align="center"><strong>Self-hosted, open-source QR code generator.</strong></p>
|
||||||
|
|
||||||
[LIVE DEMO](https://qrcode.giandonatoinverso.dev/)
|
**QRForge** creates and manages static and dynamic QR codes from a clean,
|
||||||
|
responsive control panel. It's a security-hardened, actively maintained fork
|
||||||
|
of the original [PHP Dynamic Qr code](https://github.com/giandonatoinverso/PHP-Dynamic-Qr-code)
|
||||||
|
project by Giandonato Inverso, built on [AdminLTE](https://adminlte.io/).
|
||||||
|
|
||||||
username: admin
|
- **Try it free:** [qr.ensembia.com](https://qr.ensembia.com) - fully functional OSS test
|
||||||
|
instance. Self-service signup isn't live yet, so log in with the temporary shared demo
|
||||||
password: admin
|
account `admin` / `admin` in the meantime.
|
||||||
|
- **Commercial VIP edition** (self-service create-rights, logo-embedded QR codes):
|
||||||
[DOCUMENTATION](https://giandonatoinverso.it/qrcode/documentation)
|
[www.qrforge.eu](https://www.qrforge.eu).
|
||||||
|
- **Self-host it yourself:** this repository, MIT-licensed.
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
|
||||||
- **#1 Dynamic Qr code generator on GitHub with a database to store Qr codes**
|
- Dynamic QR codes with a database-backed URL shortener
|
||||||
- Create unlimited Qr codes
|
- Create, edit, delete, enable/disable the redirect
|
||||||
- Docker compose support
|
- Download any time, bulk download/delete
|
||||||
- Control panel with 2 access levels
|
- Batch-generate from a CSV file
|
||||||
- Multi-account
|
- 16 static QR code types: Text, Email, Phone, SMS, WhatsApp, Skype, Location,
|
||||||
- Dashboard with advanced statistics on Qr codes created and on scans
|
vCard, Event/calendar, Bookmark, WiFi (incl. WPA3), PayPal, Bitcoin, 2FA,
|
||||||
- Bulk download, bulk delete
|
App Link (Android intent / universal links), Bluetooth
|
||||||
- Dynamic Qr code
|
- QR code styling: 6 export formats, foreground/background color, 4 precision
|
||||||
- Create, modify, and delete Qr codes
|
levels, 10 sizes, optional label text below the code (custom font + size),
|
||||||
- You can download your Qr codes when you want
|
optional icon shown above the code, save/load your own style presets
|
||||||
- URL shortener with redirect
|
- Address search (OpenStreetMap Nominatim) for Location QR codes
|
||||||
- Enable or disable the link redirect
|
- Built-in QR scanner (camera or image upload, decodes entirely client-side)
|
||||||
- Static Qr code
|
- Installable as a PWA
|
||||||
- Text QR Code
|
- Role-based access: `super` (full access + user management), `admin`
|
||||||
- Email QR Code
|
(scoped to their own codes and sub-users), `user` (read-only, with
|
||||||
- Phone QR Code
|
optional per-account create rights and view toggles set by an admin)
|
||||||
- Sms QR Code
|
- Dashboard with QR/scan statistics and a 7-day activity chart
|
||||||
- Whatsapp QR Code
|
- CSRF protection, login rate limiting, session hardening, audit log
|
||||||
- Skype QR Code
|
- Docker Compose setup, both a dev image and a production Nginx + PHP-FPM image
|
||||||
- Location QR Code
|
|
||||||
- Vcard QR Code
|
|
||||||
- Event/calendar QR Code
|
|
||||||
- Bookmark QR Code
|
|
||||||
- Wifi QR Code
|
|
||||||
- Paypal QR Code
|
|
||||||
- Bitcoin QR Code
|
|
||||||
- Customization of Qr codes
|
|
||||||
- 6 formats for images
|
|
||||||
- Foreground color
|
|
||||||
- Background color
|
|
||||||
- 4 levels of precision
|
|
||||||
- 10 sizes
|
|
||||||
- Responsive bootstrap-based design
|
|
||||||
- Easy to understand and expand code
|
|
||||||
- Full OOP with classes and well-documented
|
|
||||||
|
|
||||||
## What is included
|
# What is included
|
||||||
|
|
||||||
- PHP files
|
- PHP 8.4 application source
|
||||||
- .sql file with sample data
|
- Database schema + migrations
|
||||||
- JS files
|
- Docker Compose files (dev and production)
|
||||||
- CSS files
|
- CSS/JS assets
|
||||||
- Docker compose file
|
|
||||||
|
|
||||||
## Setup with docker compose
|
# Setup with Docker Compose
|
||||||
1. download docker-compose.yml file
|
|
||||||
2. Start docker stack
|
1. Clone this repository.
|
||||||
```bash
|
2. Copy `.env.example` to `.env` and set a real `DATABASE_PASSWORD` /
|
||||||
docker compose build --no-cache && docker compose up -d
|
`MYSQL_ROOT_PASSWORD`.
|
||||||
```
|
3. Start the stack:
|
||||||
3. Open your browser at http://localhost:80 and login with (username: superadmin, password: superadmin)
|
```bash
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
4. Open `http://localhost` and log in with `superadmin` / `superadmin`. You'll
|
||||||
|
be required to set a new password on first login.
|
||||||
|
|
||||||
|
For a production deployment behind a reverse proxy, use
|
||||||
|
`docker-compose.prod.yml` (Nginx + PHP-FPM) instead of the dev stack.
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
- Originally forked from [PHP Dynamic Qr code](https://github.com/giandonatoinverso/PHP-Dynamic-Qr-code)
|
||||||
|
by Giandonato Inverso.
|
||||||
|
- QR code rendering powered by [chillerlan/php-qrcode](https://github.com/chillerlan/php-qrcode).
|
||||||
|
- Admin panel UI built on [AdminLTE](https://adminlte.io/).
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT - see [LICENSE](LICENSE).
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
image: "nginx:1.27-alpine"
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.nginx
|
||||||
restart: "unless-stopped"
|
restart: "unless-stopped"
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
@@ -9,11 +11,11 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- php-dynamic-qrcode
|
- qrforge-app
|
||||||
networks:
|
networks:
|
||||||
- php-dynamic-qrcode-network
|
- qrforge-network
|
||||||
|
|
||||||
php-dynamic-qrcode:
|
qrforge-app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile.fpm
|
dockerfile: Dockerfile.fpm
|
||||||
@@ -22,7 +24,7 @@ services:
|
|||||||
TYPE: "docker"
|
TYPE: "docker"
|
||||||
QRCODE_GENERATOR: "${QRCODE_GENERATOR:-internal-chillerlan.qrcode}"
|
QRCODE_GENERATOR: "${QRCODE_GENERATOR:-internal-chillerlan.qrcode}"
|
||||||
BASE_URL: "${BASE_URL:?set BASE_URL in .env, e.g. https://qr.ensembia.com}"
|
BASE_URL: "${BASE_URL:?set BASE_URL in .env, e.g. https://qr.ensembia.com}"
|
||||||
DATABASE_HOST: "php-dynamic-qrcode-db"
|
DATABASE_HOST: "qrforge-db"
|
||||||
DATABASE_PORT: "3306"
|
DATABASE_PORT: "3306"
|
||||||
DATABASE_NAME: "${DATABASE_NAME:-qrcode}"
|
DATABASE_NAME: "${DATABASE_NAME:-qrcode}"
|
||||||
DATABASE_USER: "${DATABASE_USER:-qrcode}"
|
DATABASE_USER: "${DATABASE_USER:-qrcode}"
|
||||||
@@ -30,18 +32,18 @@ services:
|
|||||||
DATABASE_PREFIX: "${DATABASE_PREFIX:-}"
|
DATABASE_PREFIX: "${DATABASE_PREFIX:-}"
|
||||||
DATABASE_CHARSET: "${DATABASE_CHARSET:-utf8}"
|
DATABASE_CHARSET: "${DATABASE_CHARSET:-utf8}"
|
||||||
depends_on:
|
depends_on:
|
||||||
php-dynamic-qrcode-db:
|
qrforge-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- php_dynamic_qrcode_saved_qrcode_data:/var/www/qrcode-storage
|
- qrforge_qrcode_storage:/var/www/qrcode-storage
|
||||||
networks:
|
networks:
|
||||||
- php-dynamic-qrcode-network
|
- qrforge-network
|
||||||
|
|
||||||
php-dynamic-qrcode-db:
|
qrforge-db:
|
||||||
image: "mysql:8.0"
|
image: "mysql:8.0"
|
||||||
restart: "unless-stopped"
|
restart: "unless-stopped"
|
||||||
volumes:
|
volumes:
|
||||||
- php_dynamic_qrcode_db_data:/var/lib/mysql
|
- qrforge_db_data:/var/lib/mysql
|
||||||
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}"
|
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}"
|
||||||
@@ -54,12 +56,12 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
networks:
|
networks:
|
||||||
- php-dynamic-qrcode-network
|
- qrforge-network
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
php_dynamic_qrcode_db_data:
|
qrforge_db_data:
|
||||||
php_dynamic_qrcode_saved_qrcode_data:
|
qrforge_qrcode_storage:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
php-dynamic-qrcode-network:
|
qrforge-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
services:
|
services:
|
||||||
php-dynamic-qrcode:
|
qrforge-app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
TYPE: "${TYPE:-docker}"
|
TYPE: "${TYPE:-docker}"
|
||||||
QRCODE_GENERATOR: "${QRCODE_GENERATOR:-internal-chillerlan.qrcode}"
|
QRCODE_GENERATOR: "${QRCODE_GENERATOR:-internal-chillerlan.qrcode}"
|
||||||
BASE_URL: "${BASE_URL:-http://localhost}"
|
BASE_URL: "${BASE_URL:-http://localhost}"
|
||||||
DATABASE_HOST: "php-dynamic-qrcode-db"
|
DATABASE_HOST: "qrforge-db"
|
||||||
DATABASE_PORT: "3306"
|
DATABASE_PORT: "3306"
|
||||||
DATABASE_NAME: "${DATABASE_NAME:-qrcode}"
|
DATABASE_NAME: "${DATABASE_NAME:-qrcode}"
|
||||||
DATABASE_USER: "${DATABASE_USER:-qrcode}"
|
DATABASE_USER: "${DATABASE_USER:-qrcode}"
|
||||||
@@ -18,18 +18,18 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
php-dynamic-qrcode-db:
|
qrforge-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- php_dynamic_qrcode_saved_qrcode_data:/var/www/html/saved_qrcode
|
- qrforge_qrcode_storage:/var/www/qrcode-storage
|
||||||
networks:
|
networks:
|
||||||
- php-dynamic-qrcode-network
|
- qrforge-network
|
||||||
|
|
||||||
php-dynamic-qrcode-db:
|
qrforge-db:
|
||||||
image: "mysql:8.0"
|
image: "mysql:8.0"
|
||||||
restart: "unless-stopped"
|
restart: "unless-stopped"
|
||||||
volumes:
|
volumes:
|
||||||
- php_dynamic_qrcode_db_data:/var/lib/mysql
|
- qrforge_db_data:/var/lib/mysql
|
||||||
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?zet MYSQL_ROOT_PASSWORD in .env}"
|
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?zet MYSQL_ROOT_PASSWORD in .env}"
|
||||||
@@ -42,12 +42,12 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
networks:
|
networks:
|
||||||
- php-dynamic-qrcode-network
|
- qrforge-network
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
php_dynamic_qrcode_db_data:
|
qrforge_db_data:
|
||||||
php_dynamic_qrcode_saved_qrcode_data:
|
qrforge_qrcode_storage:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
php-dynamic-qrcode-network:
|
qrforge-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location ~ \.php$ {
|
location ~ \.php$ {
|
||||||
fastcgi_pass php-dynamic-qrcode:9000;
|
fastcgi_pass qrforge-app:9000;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'includes/bootstrap.php';
|
||||||
|
require_once BASE_PATH . '/includes/auth_validate.php';
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<title>About - QRForge</title>
|
||||||
|
<head>
|
||||||
|
<?php include './includes/head.php'; ?>
|
||||||
|
</head>
|
||||||
|
<body class="hold-transition sidebar-mini layout-fixed layout-navbar-fixed layout-footer-fixed">
|
||||||
|
<div class="wrapper">
|
||||||
|
<!-- Navbar -->
|
||||||
|
<?php include './includes/navbar.php'; ?>
|
||||||
|
<!-- /.navbar -->
|
||||||
|
|
||||||
|
<!-- Main Sidebar Container -->
|
||||||
|
<?php include './includes/sidebar.php'; ?>
|
||||||
|
<!-- /.Main Sidebar Container -->
|
||||||
|
|
||||||
|
<!-- Content Wrapper. Contains page content -->
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- Content Header (Page header) -->
|
||||||
|
<div class="content-header">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row mb-2">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h1 class="m-0 text-dark">About</h1>
|
||||||
|
</div><!-- /.col -->
|
||||||
|
</div><!-- /.row -->
|
||||||
|
</div><!-- /.container-fluid -->
|
||||||
|
</div>
|
||||||
|
<!-- /.content-header -->
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<section class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="card card-primary">
|
||||||
|
<div class="card-body text-center">
|
||||||
|
<img src="dist/img/brand/logo-stacked.svg" alt="QRForge" style="max-width: 220px; margin: 20px 0;">
|
||||||
|
<p class="text-muted">Self-hosted static and dynamic QR code generator. Version 3.0.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Commercial version</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
This is the free, open-source (MIT) edition of QRForge. It runs unmodified
|
||||||
|
as a live, fully functional try-out at
|
||||||
|
<a href="https://qr.ensembia.com" target="_blank">qr.ensembia.com</a> -
|
||||||
|
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>
|
||||||
|
The commercial VIP edition (paid create-rights and logo-embedded QR codes)
|
||||||
|
is a separate product built on the same OSS core - see
|
||||||
|
<a href="https://www.qrforge.eu" target="_blank">www.qrforge.eu</a> for
|
||||||
|
pricing and details.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Self-hosting</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
Prefer to run your own instance? QRForge is MIT-licensed and available on
|
||||||
|
GitHub:
|
||||||
|
<a href="https://github.com/dillardblom/QRForge-selfhosted" target="_blank">github.com/dillardblom/QRForge-selfhosted</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Credits</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
Originally forked from
|
||||||
|
<a href="https://github.com/giandonatoinverso/PHP-Dynamic-Qr-code" target="_blank">PHP Qrcode Generator by Giandonato Inverso</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
QR code rendering is powered by the
|
||||||
|
<a href="https://github.com/chillerlan/php-qrcode" target="_blank">chillerlan/php-qrcode</a>
|
||||||
|
library.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/. container-fluid -->
|
||||||
|
</section><!-- /.content -->
|
||||||
|
</div><!-- /.content-wrapper -->
|
||||||
|
|
||||||
|
<!-- Footer and scripts -->
|
||||||
|
<?php include './includes/footer.php'; ?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -99,7 +99,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -47,13 +47,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Change password - Qrcode Generator</title>
|
<title>Change password - QRForge</title>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
|
|
||||||
<body class="login-page" style="min-height: 512.391px;">
|
<body class="login-page" style="min-height: 512.391px;">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<div class="login-logo">
|
<div class="login-logo">
|
||||||
<img src="dist/img/DynamicQRCode_Original.png" style="width: 95%; height: 95%">
|
<img src="dist/img/brand/logo.svg" alt="QRForge" style="max-width: 260px;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|||||||
@@ -6,4 +6,21 @@
|
|||||||
#err-msg {
|
#err-msg {
|
||||||
display: none;
|
display: none;
|
||||||
color: red;
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List-page qr code thumbnails: fixed box, but object-fit:contain instead of
|
||||||
|
width/height attrs so taller images (e.g. icon-above-qr) don't get squashed. */
|
||||||
|
.qr-thumb-link {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.qr-thumb-img {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
object-fit: contain;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 476 B |
|
After Width: | Height: | Size: 755 B |
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 151.74 151.74" role="img" aria-labelledby="qfi-title qfi-desc">
|
||||||
|
<title id="qfi-title">QRForge icon</title>
|
||||||
|
<desc id="qfi-desc">QR-block mark with outbound arrow tile.</desc>
|
||||||
|
<g transform="translate(-8.95,-2.57)">
|
||||||
|
<rect id="block-top-left" x="5.24" y="16.81" width="42.29" height="40.70" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-mid" x="59.57" y="68.79" width="24.90" height="23.46" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-bottom-right" x="96.08" y="103.32" width="40.59" height="31.68" rx="2.5" fill="#334155" />
|
||||||
|
<path id="block-bottom-left-L" d="M 5.24,71.29 Q 5.24,68.79 7.74,68.79 L 45.03,68.79 Q 47.53,68.79 47.53,71.29 L 47.53,103.32 Q 47.53,103.32 47.53,103.32 L 81.97,103.32 Q 84.47,103.32 84.47,105.82 L 84.47,132.50 Q 84.47,135.00 81.97,135.00 L 7.74,135.00 Q 5.24,135.00 5.24,132.50 Z" fill="#334155" />
|
||||||
|
<path id="arrow-tile" d="M 105.68,6.94 Q 104.67,5.88 106.13,5.88 L 145.89,5.88 Q 148.39,5.88 148.39,8.38 L 148.39,44.14 Q 148.39,46.64 146.42,45.11 L 133.00,34.67 Q 133.00,34.67 133.00,34.67 L 112.50,56.87 Q 112.50,56.87 112.50,56.87 L 134.08,56.87 Q 136.58,56.87 136.58,59.37 L 136.58,89.50 Q 136.58,92.00 134.08,92.00 L 98.63,92.00 Q 96.13,92.00 96.13,89.50 L 96.13,56.87 Q 96.13,56.87 96.13,56.87 L 62.10,56.87 Q 59.60,56.87 59.60,54.37 L 59.60,19.60 Q 59.60,17.10 62.10,17.10 L 93.63,17.10 Q 96.13,17.10 96.13,19.60 L 96.13,41.00 Q 96.13,41.00 96.13,41.00 L 97.00,42.17 Q 97.00,42.17 97.00,42.17 L 117.19,22.73 Q 118.99,21.00 117.27,19.18 L 107.68,9.06 Q 106.68,8.00 105.68,6.94 Z" fill="#2563EB" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 151.74 151.74" role="img" aria-labelledby="qfi-title qfi-desc">
|
||||||
|
<title id="qfi-title">QRForge icon</title>
|
||||||
|
<desc id="qfi-desc">QR-block mark with outbound arrow tile.</desc>
|
||||||
|
<g transform="translate(-8.95,-2.57)">
|
||||||
|
<rect id="block-top-left" x="5.24" y="16.81" width="42.29" height="40.70" rx="2.5" fill="#FFFFFF" />
|
||||||
|
<rect id="block-mid" x="59.57" y="68.79" width="24.90" height="23.46" rx="2.5" fill="#FFFFFF" />
|
||||||
|
<rect id="block-bottom-right" x="96.08" y="103.32" width="40.59" height="31.68" rx="2.5" fill="#FFFFFF" />
|
||||||
|
<path id="block-bottom-left-L" d="M 5.24,71.29 Q 5.24,68.79 7.74,68.79 L 45.03,68.79 Q 47.53,68.79 47.53,71.29 L 47.53,103.32 Q 47.53,103.32 47.53,103.32 L 81.97,103.32 Q 84.47,103.32 84.47,105.82 L 84.47,132.50 Q 84.47,135.00 81.97,135.00 L 7.74,135.00 Q 5.24,135.00 5.24,132.50 Z" fill="#FFFFFF" />
|
||||||
|
<path id="arrow-tile" d="M 105.68,6.94 Q 104.67,5.88 106.13,5.88 L 145.89,5.88 Q 148.39,5.88 148.39,8.38 L 148.39,44.14 Q 148.39,46.64 146.42,45.11 L 133.00,34.67 Q 133.00,34.67 133.00,34.67 L 112.50,56.87 Q 112.50,56.87 112.50,56.87 L 134.08,56.87 Q 136.58,56.87 136.58,59.37 L 136.58,89.50 Q 136.58,92.00 134.08,92.00 L 98.63,92.00 Q 96.13,92.00 96.13,89.50 L 96.13,56.87 Q 96.13,56.87 96.13,56.87 L 62.10,56.87 Q 59.60,56.87 59.60,54.37 L 59.60,19.60 Q 59.60,17.10 62.10,17.10 L 93.63,17.10 Q 96.13,17.10 96.13,19.60 L 96.13,41.00 Q 96.13,41.00 96.13,41.00 L 97.00,42.17 Q 97.00,42.17 97.00,42.17 L 117.19,22.73 Q 118.99,21.00 117.27,19.18 L 107.68,9.06 Q 106.68,8.00 105.68,6.94 Z" fill="#2563EB" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,11 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 151.74 151.74" role="img" aria-labelledby="qfi-title qfi-desc">
|
||||||
|
<title id="qfi-title">QRForge icon</title>
|
||||||
|
<desc id="qfi-desc">QR-block mark with outbound arrow tile.</desc>
|
||||||
|
<g transform="translate(-8.95,-2.57)">
|
||||||
|
<rect id="block-top-left" x="5.24" y="16.81" width="42.29" height="40.70" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-mid" x="59.57" y="68.79" width="24.90" height="23.46" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-bottom-right" x="96.08" y="103.32" width="40.59" height="31.68" rx="2.5" fill="#334155" />
|
||||||
|
<path id="block-bottom-left-L" d="M 5.24,71.29 Q 5.24,68.79 7.74,68.79 L 45.03,68.79 Q 47.53,68.79 47.53,71.29 L 47.53,103.32 Q 47.53,103.32 47.53,103.32 L 81.97,103.32 Q 84.47,103.32 84.47,105.82 L 84.47,132.50 Q 84.47,135.00 81.97,135.00 L 7.74,135.00 Q 5.24,135.00 5.24,132.50 Z" fill="#334155" />
|
||||||
|
<path id="arrow-tile" d="M 105.68,6.94 Q 104.67,5.88 106.13,5.88 L 145.89,5.88 Q 148.39,5.88 148.39,8.38 L 148.39,44.14 Q 148.39,46.64 146.42,45.11 L 133.00,34.67 Q 133.00,34.67 133.00,34.67 L 112.50,56.87 Q 112.50,56.87 112.50,56.87 L 134.08,56.87 Q 136.58,56.87 136.58,59.37 L 136.58,89.50 Q 136.58,92.00 134.08,92.00 L 98.63,92.00 Q 96.13,92.00 96.13,89.50 L 96.13,56.87 Q 96.13,56.87 96.13,56.87 L 62.10,56.87 Q 59.60,56.87 59.60,54.37 L 59.60,19.60 Q 59.60,17.10 62.10,17.10 L 93.63,17.10 Q 96.13,17.10 96.13,19.60 L 96.13,41.00 Q 96.13,41.00 96.13,41.00 L 97.00,42.17 Q 97.00,42.17 97.00,42.17 L 117.19,22.73 Q 118.99,21.00 117.27,19.18 L 107.68,9.06 Q 106.68,8.00 105.68,6.94 Z" fill="#2563EB" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 236.20 246.50" role="img" aria-labelledby="qfs-title qfs-desc">
|
||||||
|
<title id="qfs-title">QRForge stacked logo</title>
|
||||||
|
<desc id="qfs-desc">Stacked QRForge logo.</desc>
|
||||||
|
<g transform="translate(33.28,14.75)">
|
||||||
|
<rect id="block-top-left" x="5.24" y="16.81" width="42.29" height="40.70" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-mid" x="59.57" y="68.79" width="24.90" height="23.46" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-bottom-right" x="96.08" y="103.32" width="40.59" height="31.68" rx="2.5" fill="#334155" />
|
||||||
|
<path id="block-bottom-left-L" d="M 5.24,71.29 Q 5.24,68.79 7.74,68.79 L 45.03,68.79 Q 47.53,68.79 47.53,71.29 L 47.53,103.32 Q 47.53,103.32 47.53,103.32 L 81.97,103.32 Q 84.47,103.32 84.47,105.82 L 84.47,132.50 Q 84.47,135.00 81.97,135.00 L 7.74,135.00 Q 5.24,135.00 5.24,132.50 Z" fill="#334155" />
|
||||||
|
<path id="arrow-tile" d="M 105.68,6.94 Q 104.67,5.88 106.13,5.88 L 145.89,5.88 Q 148.39,5.88 148.39,8.38 L 148.39,44.14 Q 148.39,46.64 146.42,45.11 L 133.00,34.67 Q 133.00,34.67 133.00,34.67 L 112.50,56.87 Q 112.50,56.87 112.50,56.87 L 134.08,56.87 Q 136.58,56.87 136.58,59.37 L 136.58,89.50 Q 136.58,92.00 134.08,92.00 L 98.63,92.00 Q 96.13,92.00 96.13,89.50 L 96.13,56.87 Q 96.13,56.87 96.13,56.87 L 62.10,56.87 Q 59.60,56.87 59.60,54.37 L 59.60,19.60 Q 59.60,17.10 62.10,17.10 L 93.63,17.10 Q 96.13,17.10 96.13,19.60 L 96.13,41.00 Q 96.13,41.00 96.13,41.00 L 97.00,42.17 Q 97.00,42.17 97.00,42.17 L 117.19,22.73 Q 118.99,21.00 117.27,19.18 L 107.68,9.06 Q 106.68,8.00 105.68,6.94 Z" fill="#2563EB" />
|
||||||
|
</g>
|
||||||
|
<text x="118.10" y="203.67" text-anchor="middle" font-family="Inter, Manrope, Geist, Arial, sans-serif" font-size="48.39" font-weight="700" letter-spacing="-3.43" fill="#334155">QRForge</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5.24 5.88 573.81 145.12" role="img" aria-labelledby="qf-title qf-desc">
|
||||||
|
<title id="qf-title">QRForge logo</title>
|
||||||
|
<desc id="qf-desc">QRForge wordmark with a QR-block mark and outbound arrow tile.</desc>
|
||||||
|
<g id="icon">
|
||||||
|
<rect id="block-top-left" x="5.24" y="16.81" width="42.29" height="40.70" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-mid" x="59.57" y="68.79" width="24.90" height="23.46" rx="2.5" fill="#334155" />
|
||||||
|
<rect id="block-bottom-right" x="96.08" y="103.32" width="40.59" height="31.68" rx="2.5" fill="#334155" />
|
||||||
|
<path id="block-bottom-left-L" d="M 5.24,71.29 Q 5.24,68.79 7.74,68.79 L 45.03,68.79 Q 47.53,68.79 47.53,71.29 L 47.53,103.32 Q 47.53,103.32 47.53,103.32 L 81.97,103.32 Q 84.47,103.32 84.47,105.82 L 84.47,132.50 Q 84.47,135.00 81.97,135.00 L 7.74,135.00 Q 5.24,135.00 5.24,132.50 Z" fill="#334155" />
|
||||||
|
<path id="arrow-tile" d="M 105.68,6.94 Q 104.67,5.88 106.13,5.88 L 145.89,5.88 Q 148.39,5.88 148.39,8.38 L 148.39,44.14 Q 148.39,46.64 146.42,45.11 L 133.00,34.67 Q 133.00,34.67 133.00,34.67 L 112.50,56.87 Q 112.50,56.87 112.50,56.87 L 134.08,56.87 Q 136.58,56.87 136.58,59.37 L 136.58,89.50 Q 136.58,92.00 134.08,92.00 L 98.63,92.00 Q 96.13,92.00 96.13,89.50 L 96.13,56.87 Q 96.13,56.87 96.13,56.87 L 62.10,56.87 Q 59.60,56.87 59.60,54.37 L 59.60,19.60 Q 59.60,17.10 62.10,17.10 L 93.63,17.10 Q 96.13,17.10 96.13,19.60 L 96.13,41.00 Q 96.13,41.00 96.13,41.00 L 97.00,42.17 Q 97.00,42.17 97.00,42.17 L 117.19,22.73 Q 118.99,21.00 117.27,19.18 L 107.68,9.06 Q 106.68,8.00 105.68,6.94 Z" fill="#2563EB" />
|
||||||
|
</g>
|
||||||
|
<text id="wordmark" x="177" y="101" font-family="Inter, Manrope, Geist, Arial, sans-serif" font-size="103" font-weight="700" letter-spacing="-7.3" fill="#334155">QRForge</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,69 @@
|
|||||||
|
(function () {
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
var searchInput = document.getElementById('location_search');
|
||||||
|
var searchBtn = document.getElementById('location_search_btn');
|
||||||
|
var resultsBox = document.getElementById('location_search_results');
|
||||||
|
var latInput = document.getElementById('latitude');
|
||||||
|
var lngInput = document.getElementById('longitude');
|
||||||
|
|
||||||
|
if (!searchInput || !searchBtn || !resultsBox || !latInput || !lngInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearResults() {
|
||||||
|
resultsBox.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch() {
|
||||||
|
var query = searchInput.value.trim();
|
||||||
|
if (!query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearResults();
|
||||||
|
resultsBox.innerHTML = '<div class="list-group-item">Searching...</div>';
|
||||||
|
|
||||||
|
fetch('https://nominatim.openstreetmap.org/search?format=json&limit=5&q=' + encodeURIComponent(query))
|
||||||
|
.then(function (response) { return response.json(); })
|
||||||
|
.then(function (results) {
|
||||||
|
clearResults();
|
||||||
|
|
||||||
|
if (!results.length) {
|
||||||
|
resultsBox.innerHTML = '<div class="list-group-item">No results found.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
results.forEach(function (place) {
|
||||||
|
var item = document.createElement('button');
|
||||||
|
item.type = 'button';
|
||||||
|
item.className = 'list-group-item list-group-item-action';
|
||||||
|
item.textContent = place.display_name;
|
||||||
|
item.addEventListener('click', function () {
|
||||||
|
latInput.value = place.lat;
|
||||||
|
lngInput.value = place.lon;
|
||||||
|
searchInput.value = place.display_name;
|
||||||
|
clearResults();
|
||||||
|
});
|
||||||
|
resultsBox.appendChild(item);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
resultsBox.innerHTML = '<div class="list-group-item text-danger">Search failed (network error).</div>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
searchBtn.addEventListener('click', doSearch);
|
||||||
|
searchInput.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
doSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
if (e.target !== searchInput && !resultsBox.contains(e.target)) {
|
||||||
|
clearResults();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -95,9 +95,18 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('#foreground, #background').forEach(function (input) {
|
document.querySelectorAll('#foreground, #background').forEach(function (input) {
|
||||||
input.addEventListener('change', function () {
|
// bootstrap-colorpicker sets the value and fires 'change' via jQuery's
|
||||||
updateStylePreview(scopeOf(input));
|
// synthetic .trigger(), which a native addEventListener never sees - so the
|
||||||
});
|
// preview only updates via jQuery's event binding, not the native one below.
|
||||||
|
if (window.jQuery) {
|
||||||
|
jQuery(input).on('change', function () {
|
||||||
|
updateStylePreview(scopeOf(input));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
input.addEventListener('change', function () {
|
||||||
|
updateStylePreview(scopeOf(input));
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('select[name="level"]').forEach(function (select) {
|
document.querySelectorAll('select[name="level"]').forEach(function (select) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ if($_SERVER["REQUEST_METHOD"] === "POST" && !isset($_POST["edit"]) && !isset($_P
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ $total_pages = $db->totalPages;
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
|
After Width: | Height: | Size: 31 KiB |
@@ -117,27 +117,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-12 mb-2">
|
<div class="col-sm-12 mb-2">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="filename">Filename *</label>
|
|
||||||
<input type="text" name="filename" value="" placeholder="My first Qrcode" class="form-control error" required="required" id="filename">
|
|
||||||
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<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>
|
||||||
@@ -177,13 +157,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if($_SESSION['type'] === 'super') { ?>
|
|
||||||
<div class="col-sm-12 mb-2">
|
<div class="col-sm-12 mb-2">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="filename">Filename *</label>
|
||||||
|
<input type="text" name="filename" value="" placeholder="My first Qrcode" class="form-control error" required="required" id="filename">
|
||||||
|
</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') { ?>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="id_owner">Owner *</label>
|
<label for="id_owner">Owner *</label>
|
||||||
<select name="id_owner" class="form-control">
|
<select name="id_owner" id="id_owner" class="form-control">
|
||||||
<option value="">All (shared with every admin)</option>
|
<option value="">All (shared with every admin)</option>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
@@ -199,9 +198,9 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php } else { ?>
|
||||||
|
<input type="hidden" name="id_owner" value="<?php echo $_SESSION["user_id"];?>"/>
|
||||||
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php } else { ?>
|
|
||||||
<input type="hidden" name="id_owner" value="<?php echo $_SESSION["user_id"];?>"/>
|
|
||||||
<?php } ?>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ 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-3">
|
<div class="col-6 col-md-3">
|
||||||
<label> </label>
|
<label>Randomize</label>
|
||||||
<button type="button" id="random_style_btn" class="btn btn-outline-secondary btn-block">
|
<button type="button" id="random_style_btn" class="btn btn-outline-secondary btn-block">
|
||||||
<i class="fa fa-dice"></i> Random style
|
<i class="fa fa-dice"></i> Random style
|
||||||
</button>
|
</button>
|
||||||
@@ -113,32 +113,7 @@ 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-sm-4">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="filename">Filename *</label>
|
|
||||||
<input type="text" name="filename" value="" placeholder="My first Qrcode" class="form-control error" required="required" id = "filename">
|
|
||||||
|
|
||||||
</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>
|
|
||||||
|
|
||||||
<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,31 +153,55 @@ if (QRCODE_GENERATOR === "internal-chillerlan.qrcode") {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if($_SESSION['type'] === 'super') { ?>
|
<div class="col-sm-12 mb-2">
|
||||||
<div class="col-sm-12 mb-2">
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col-sm-4">
|
||||||
<div class="col-sm-4">
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="filename">Filename *</label>
|
||||||
<label for="id_owner">Owner *</label>
|
<input type="text" name="filename" value="" placeholder="My first Qrcode" class="form-control error" required="required" id="filename">
|
||||||
<select name="id_owner" class="form-control">
|
|
||||||
<option value="">All (shared with every admin)</option>
|
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once BASE_PATH . '/lib/Users/Users.php';
|
|
||||||
$users_instance = new Users();
|
|
||||||
$users = $users_instance->getAllUsers();
|
|
||||||
|
|
||||||
foreach ($users as $user) {
|
|
||||||
$is_self = (int) $user["id"] === (int) $_SESSION["user_id"];
|
|
||||||
?>
|
|
||||||
<option value="<?php echo $user["id"];?>" <?php echo $is_self ? 'selected' : ''; ?>><?php echo $user["username"];?></option>
|
|
||||||
<?php } ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</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') { ?>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="id_owner">Owner *</label>
|
||||||
|
<select name="id_owner" id="id_owner" class="form-control">
|
||||||
|
<option value="">All (shared with every admin)</option>
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once BASE_PATH . '/lib/Users/Users.php';
|
||||||
|
$users_instance = new Users();
|
||||||
|
$users = $users_instance->getAllUsers();
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$is_self = (int) $user["id"] === (int) $_SESSION["user_id"];
|
||||||
|
?>
|
||||||
|
<option value="<?php echo $user["id"];?>" <?php echo $is_self ? 'selected' : ''; ?>><?php echo $user["username"];?></option>
|
||||||
|
<?php } ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php } else { ?>
|
||||||
|
<input type="hidden" name="id_owner" value="<?php echo $_SESSION["user_id"];?>"/>
|
||||||
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
<?php } else { ?>
|
</div>
|
||||||
<input type="hidden" name="id_owner" value="<?php echo $_SESSION["user_id"];?>"/>
|
|
||||||
<?php } ?>
|
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -2,26 +2,41 @@
|
|||||||
<?php echo csrf_field(); ?>
|
<?php echo csrf_field(); ?>
|
||||||
<?php include BASE_PATH.'/forms/qrcode_options.php'; ?>
|
<?php include BASE_PATH.'/forms/qrcode_options.php'; ?>
|
||||||
<!-- Input forms -->
|
<!-- Input forms -->
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-8">
|
||||||
<div class="form-group">
|
<div class="form-group" style="position: relative;">
|
||||||
<label>Latitude *</label>
|
<label for="location_search">Search address</label>
|
||||||
<input type="text" name="latitude" value="" placeholder="40.7127753" class="form-control">
|
<div class="input-group">
|
||||||
|
<input type="text" id="location_search" class="form-control" placeholder="Search for an address or place...">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button type="button" id="location_search_btn" class="btn btn-outline-secondary"><i class="fa fa-search"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="location_search_results" class="list-group" style="position:absolute;z-index:1000;width:100%;"></div>
|
||||||
|
<small class="form-text text-muted">Looks up coordinates via OpenStreetMap Nominatim (your search leaves this server and goes to nominatim.openstreetmap.org). Or enter coordinates directly below.</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Longitude *</label>
|
<label for="latitude">Latitude *</label>
|
||||||
<input type="text" name="longitude" value="" placeholder="-74.0059728" class="form-control">
|
<input type="text" name="latitude" id="latitude" value="" placeholder="40.7127753" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="longitude">Longitude *</label>
|
||||||
|
<input type="text" name="longitude" id="longitude" value="" placeholder="-74.0059728" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<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-3">
|
<div class="col-6 col-md-3">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="dist/js/location-search.js"></script>
|
||||||
</form>
|
</form>
|
||||||
@@ -70,7 +70,11 @@
|
|||||||
<td><?php echo htmlspecialchars($row['identifier']); ?></td>
|
<td><?php echo htmlspecialchars($row['identifier']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($row['link']); ?></td>
|
<td><?php echo htmlspecialchars($row['link']); ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php echo '<img src="qrcode_image.php?type=dynamic&id='.$row['id'].'" width="100" height="100">'; ?>
|
<a href="#" class="qr-thumb-link" data-toggle="modal" data-target="#preview-modal"
|
||||||
|
data-qr-src="qrcode_image.php?type=dynamic&id=<?php echo $row['id']; ?>"
|
||||||
|
data-qr-name="<?php echo htmlspecialchars($row['filename']); ?>">
|
||||||
|
<img src="qrcode_image.php?type=dynamic&id=<?php echo $row['id']; ?>" class="qr-thumb-img" alt="QR code for <?php echo htmlspecialchars($row['filename']); ?>">
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td><?php echo htmlspecialchars($row['scan']); ?></td>
|
<td><?php echo htmlspecialchars($row['scan']); ?></td>
|
||||||
<td><?php echo htmlspecialchars($row['state']); ?></td>
|
<td><?php echo htmlspecialchars($row['state']); ?></td>
|
||||||
@@ -135,6 +139,32 @@
|
|||||||
<!-- /.Delete Confirmation Modal -->
|
<!-- /.Delete Confirmation Modal -->
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Qr Code Preview Modal -->
|
||||||
|
<div class="modal fade" id="preview-modal" role="dialog">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="preview-modal-title">QR code preview</h4>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-center">
|
||||||
|
<img id="preview-modal-img" src="" alt="" style="max-width:100%;max-height:70vh;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.Qr Code Preview Modal -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.qr-thumb-link').forEach(function (link) {
|
||||||
|
link.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('preview-modal-img').src = link.getAttribute('data-qr-src');
|
||||||
|
document.getElementById('preview-modal-title').textContent = link.getAttribute('data-qr-name');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const deleteButtons = document.querySelectorAll('.delete_btn');
|
const deleteButtons = document.querySelectorAll('.delete_btn');
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,11 @@
|
|||||||
<td><?php echo htmlspecialchars($row['type']); ?></td>
|
<td><?php echo htmlspecialchars($row['type']); ?></td>
|
||||||
<td><?php echo htmlspecialchars_decode($row['content']); ?></td>
|
<td><?php echo htmlspecialchars_decode($row['content']); ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php echo '<img src="qrcode_image.php?type=static&id='.$row['id'].'" width="100" height="100">'; ?>
|
<a href="#" class="qr-thumb-link" data-toggle="modal" data-target="#preview-modal"
|
||||||
|
data-qr-src="qrcode_image.php?type=static&id=<?php echo $row['id']; ?>"
|
||||||
|
data-qr-name="<?php echo htmlspecialchars($row['filename']); ?>">
|
||||||
|
<img src="qrcode_image.php?type=static&id=<?php echo $row['id']; ?>" class="qr-thumb-img" alt="QR code for <?php echo htmlspecialchars($row['filename']); ?>">
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (!$is_readonly_user): ?>
|
<?php if (!$is_readonly_user): ?>
|
||||||
@@ -131,6 +135,32 @@
|
|||||||
<!-- /.Delete Confirmation Modal -->
|
<!-- /.Delete Confirmation Modal -->
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Qr Code Preview Modal -->
|
||||||
|
<div class="modal fade" id="preview-modal" role="dialog">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="preview-modal-title">QR code preview</h4>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-center">
|
||||||
|
<img id="preview-modal-img" src="" alt="" style="max-width:100%;max-height:70vh;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.Qr Code Preview Modal -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.qr-thumb-link').forEach(function (link) {
|
||||||
|
link.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('preview-modal-img').src = link.getAttribute('data-qr-src');
|
||||||
|
document.getElementById('preview-modal-title').textContent = link.getAttribute('data-qr-name');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const deleteButtons = document.querySelectorAll('.delete_btn');
|
const deleteButtons = document.querySelectorAll('.delete_btn');
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
<!-- Main Footer -->
|
<!-- Main Footer -->
|
||||||
<footer class="main-footer text-sm">
|
<footer class="main-footer text-sm">
|
||||||
<strong><a href="https://github.com/giandonatoinverso/PHP-Dynamic-Qr-code" target="_blank">PHP Qrcode Generator</a> by </strong> Giandonato Inverso
|
<strong><a href="https://www.qrforge.eu" target="_blank">QRForge</a></strong> -
|
||||||
|
<a href="./about.php">About</a> / credits
|
||||||
<div class="float-right d-none d-sm-inline-block">
|
<div class="float-right d-none d-sm-inline-block">
|
||||||
<b>Version</b> 2.3.0
|
<b>Version</b> 3.0
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="csrf-token" content="<?php echo csrf_token(); ?>">
|
<meta name="csrf-token" content="<?php echo csrf_token(); ?>">
|
||||||
<meta name="theme-color" content="#007bff">
|
<meta name="theme-color" content="#2563EB">
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
<link rel="apple-touch-icon" href="dist/img/icon-192.png">
|
<link rel="icon" href="dist/img/brand/favicon.svg" type="image/svg+xml">
|
||||||
|
<link rel="icon" href="dist/img/brand/favicon-32.png" sizes="32x32" type="image/png">
|
||||||
|
<link rel="icon" href="dist/img/brand/favicon-16.png" sizes="16x16" type="image/png">
|
||||||
|
<link rel="apple-touch-icon" href="dist/img/brand/apple-touch-icon.png">
|
||||||
|
|
||||||
<!-- Font Awesome Icons -->
|
<!-- Font Awesome Icons -->
|
||||||
<link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css">
|
<link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css">
|
||||||
|
|||||||
@@ -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');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
||||||
<!-- Brand Logo -->
|
<!-- Brand Logo -->
|
||||||
<a href="./index.php" class="brand-link">
|
<a href="./index.php" class="brand-link">
|
||||||
<img src="dist/img/Symbol_WhiteBlue.png" alt="Logo" class="brand-image"
|
<img src="dist/img/brand/icon-inverse.svg" alt="QRForge" class="brand-image"
|
||||||
style="opacity: .8">
|
style="opacity: .8">
|
||||||
<span class="brand-text font-weight-light">Qrcode Generator</span>
|
<span class="brand-text font-weight-light">QRForge</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
@@ -53,20 +53,20 @@
|
|||||||
<ul class="nav nav-treeview">
|
<ul class="nav nav-treeview">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="./dynamic_qrcodes.php" <?php echo ((substr(CURRENT_PAGE, 0, 19) == 'dynamic_qrcodes.php')) ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
<a href="./dynamic_qrcodes.php" <?php echo ((substr(CURRENT_PAGE, 0, 19) == 'dynamic_qrcodes.php')) ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
<i class="far fa-circle nav-icon"></i>
|
<i class="fas fa-angle-right nav-icon"></i>
|
||||||
<p>List all</p>
|
<p>List all</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if ($_SESSION['type'] !== 'user'): ?>
|
<?php if ($_SESSION['type'] !== 'user'): ?>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="./dynamic_qrcode.php" <?php echo (CURRENT_PAGE == 'dynamic_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
<a href="./dynamic_qrcode.php" <?php echo (CURRENT_PAGE == 'dynamic_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
<i class="far fa-circle nav-icon"></i>
|
<i class="fas fa-angle-right nav-icon"></i>
|
||||||
<p>Add new</p>
|
<p>Add new</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="./batch_qrcode.php" <?php echo (CURRENT_PAGE == 'batch_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
<a href="./batch_qrcode.php" <?php echo (CURRENT_PAGE == 'batch_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
<i class="far fa-circle nav-icon"></i>
|
<i class="fas fa-angle-right nav-icon"></i>
|
||||||
<p>Batch create (CSV)</p>
|
<p>Batch create (CSV)</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -86,14 +86,14 @@
|
|||||||
<ul class="nav nav-treeview">
|
<ul class="nav nav-treeview">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="./static_qrcodes.php" <?php echo ((substr(CURRENT_PAGE, 0, 18) == 'static_qrcodes.php')) ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
<a href="./static_qrcodes.php" <?php echo ((substr(CURRENT_PAGE, 0, 18) == 'static_qrcodes.php')) ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
<i class="far fa-circle nav-icon"></i>
|
<i class="fas fa-angle-right nav-icon"></i>
|
||||||
<p>List all</p>
|
<p>List all</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if ($_SESSION['type'] !== 'user'): ?>
|
<?php if ($_SESSION['type'] !== 'user'): ?>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="./static_qrcode.php" <?php echo (CURRENT_PAGE == 'static_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
<a href="./static_qrcode.php" <?php echo (CURRENT_PAGE == 'static_qrcode.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
<i class="far fa-circle nav-icon"></i>
|
<i class="fas fa-angle-right nav-icon"></i>
|
||||||
<p>Add new</p>
|
<p>Add new</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@@ -109,6 +109,12 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="./about.php" <?php echo (CURRENT_PAGE == 'about.php') ? ' class="nav-link active"' : ' class="nav-link"'; ?>>
|
||||||
|
<i class="fas fa-info-circle nav-icon"></i>
|
||||||
|
<p>About</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<!-- /.sidebar-menu -->
|
<!-- /.sidebar-menu -->
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ foreach ($createdQrcode_static as $row) {
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qr Code Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
@@ -120,29 +120,33 @@ foreach ($createdQrcode_static as $row) {
|
|||||||
</div><!-- /.col -->
|
</div><!-- /.col -->
|
||||||
|
|
||||||
<div class="col-12 col-sm-6 col-md-3">
|
<div class="col-12 col-sm-6 col-md-3">
|
||||||
<div class="info-box mb-3 bg-success">
|
<a href="dynamic_qrcodes.php" class="d-block">
|
||||||
<span class="info-box-icon"><i class="fa fa-qrcode"></i></span>
|
<div class="info-box mb-3 bg-success">
|
||||||
|
<span class="info-box-icon"><i class="fa fa-qrcode"></i></span>
|
||||||
|
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
<span class="info-box-text">Dynamic Qr codes</span>
|
<span class="info-box-text">Dynamic Qr codes</span>
|
||||||
<span class="info-box-number"><?php echo $numQrcode_dynamic; ?></span>
|
<span class="info-box-number"><?php echo $numQrcode_dynamic; ?></span>
|
||||||
</div><!-- /.info-box-content -->
|
</div><!-- /.info-box-content -->
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</div><!-- /.col -->
|
</div><!-- /.col -->
|
||||||
|
|
||||||
<!-- fix for small devices only -->
|
<!-- fix for small devices only -->
|
||||||
<div class="clearfix hidden-md-up"></div>
|
<div class="clearfix hidden-md-up"></div>
|
||||||
|
|
||||||
<div class="col-12 col-sm-6 col-md-3">
|
<div class="col-12 col-sm-6 col-md-3">
|
||||||
<div class="info-box mb-3 bg-danger">
|
<a href="static_qrcodes.php" class="d-block">
|
||||||
<span class="info-box-icon"><i class="fa fa-qrcode"></i></span>
|
<div class="info-box mb-3 bg-danger">
|
||||||
|
<span class="info-box-icon"><i class="fa fa-qrcode"></i></span>
|
||||||
|
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
<span class="info-box-text">Static QR codes</span>
|
<span class="info-box-text">Static QR codes</span>
|
||||||
<span class="info-box-number"><?php echo $numQrcode_static; ?></span>
|
<span class="info-box-number"><?php echo $numQrcode_static; ?></span>
|
||||||
</div><!-- /.info-box-content -->
|
</div><!-- /.info-box-content -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</div><!-- /.col -->
|
</div><!-- /.col -->
|
||||||
|
|
||||||
<div class="col-12 col-sm-6 col-md-3">
|
<div class="col-12 col-sm-6 col-md-3">
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ class Qrcode {
|
|||||||
$iconWidth = imagesx($icon);
|
$iconWidth = imagesx($icon);
|
||||||
$iconHeight = imagesy($icon);
|
$iconHeight = imagesy($icon);
|
||||||
|
|
||||||
$maxIconHeight = (int) ($height * 0.25);
|
$maxIconHeight = (int) ($height * 0.625);
|
||||||
$scale = min($maxIconHeight / $iconHeight, ($width * 0.6) / $iconWidth, 1);
|
$scale = min($maxIconHeight / $iconHeight, ($width * 0.6) / $iconWidth, 1);
|
||||||
$targetWidth = max(1, (int) ($iconWidth * $scale));
|
$targetWidth = max(1, (int) ($iconWidth * $scale));
|
||||||
$targetHeight = max(1, (int) ($iconHeight * $scale));
|
$targetHeight = max(1, (int) ($iconHeight * $scale));
|
||||||
@@ -207,9 +207,12 @@ class Qrcode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getQrcode($id) {
|
public function getQrcode($id) {
|
||||||
|
require_once BASE_PATH . '/includes/security.php';
|
||||||
|
|
||||||
$db = getDbInstance();
|
$db = getDbInstance();
|
||||||
|
|
||||||
$db->where('id', $id);
|
$db->where('id', $id);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$result = $db->getOne($this->table);
|
$result = $db->getOne($this->table);
|
||||||
|
|
||||||
if($result !== NULL)
|
if($result !== NULL)
|
||||||
@@ -531,6 +534,7 @@ class Qrcode {
|
|||||||
|
|
||||||
if(!file_exists(SAVED_QRCODE_DIRECTORY.$data_to_db['filename'].'.'.$old_qrcode["format"]) || $data_to_db['filename'] == $input_data["old_filename"]){
|
if(!file_exists(SAVED_QRCODE_DIRECTORY.$data_to_db['filename'].'.'.$old_qrcode["format"]) || $data_to_db['filename'] == $input_data["old_filename"]){
|
||||||
$db->where('id', $input_data["id"]);
|
$db->where('id', $input_data["id"]);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$stat = $db->update($this->table, $data_to_db);
|
$stat = $db->update($this->table, $data_to_db);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@@ -563,6 +567,7 @@ class Qrcode {
|
|||||||
$qrcode = $this->getQrcode($id);
|
$qrcode = $this->getQrcode($id);
|
||||||
|
|
||||||
$db->where('id', $id);
|
$db->where('id', $id);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$status = $db->delete($this->table);
|
$status = $db->delete($this->table);
|
||||||
|
|
||||||
if ($status) {
|
if ($status) {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class Qrcode {
|
|||||||
$iconWidth = imagesx($icon);
|
$iconWidth = imagesx($icon);
|
||||||
$iconHeight = imagesy($icon);
|
$iconHeight = imagesy($icon);
|
||||||
|
|
||||||
$maxIconHeight = (int) ($height * 0.25);
|
$maxIconHeight = (int) ($height * 0.625);
|
||||||
$scale = min($maxIconHeight / $iconHeight, ($width * 0.6) / $iconWidth, 1);
|
$scale = min($maxIconHeight / $iconHeight, ($width * 0.6) / $iconWidth, 1);
|
||||||
$targetWidth = max(1, (int) ($iconWidth * $scale));
|
$targetWidth = max(1, (int) ($iconWidth * $scale));
|
||||||
$targetHeight = max(1, (int) ($iconHeight * $scale));
|
$targetHeight = max(1, (int) ($iconHeight * $scale));
|
||||||
@@ -192,9 +192,12 @@ class Qrcode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getQrcode($id) {
|
public function getQrcode($id) {
|
||||||
|
require_once BASE_PATH . '/includes/security.php';
|
||||||
|
|
||||||
$db = getDbInstance();
|
$db = getDbInstance();
|
||||||
|
|
||||||
$db->where('id', $id);
|
$db->where('id', $id);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$result = $db->getOne($this->table);
|
$result = $db->getOne($this->table);
|
||||||
|
|
||||||
if($result !== NULL)
|
if($result !== NULL)
|
||||||
@@ -376,6 +379,7 @@ class Qrcode {
|
|||||||
|
|
||||||
if(!file_exists(SAVED_QRCODE_DIRECTORY.$data_to_db['filename'].'.'.$old_qrcode["format"]) || $data_to_db['filename'] == $input_data["old_filename"]){
|
if(!file_exists(SAVED_QRCODE_DIRECTORY.$data_to_db['filename'].'.'.$old_qrcode["format"]) || $data_to_db['filename'] == $input_data["old_filename"]){
|
||||||
$db->where('id', $input_data["id"]);
|
$db->where('id', $input_data["id"]);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$stat = $db->update($this->table, $data_to_db);
|
$stat = $db->update($this->table, $data_to_db);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@@ -408,6 +412,7 @@ class Qrcode {
|
|||||||
$qrcode = $this->getQrcode($id);
|
$qrcode = $this->getQrcode($id);
|
||||||
|
|
||||||
$db->where('id', $id);
|
$db->where('id', $id);
|
||||||
|
qr_apply_owner_scope($db);
|
||||||
$status = $db->delete($this->table);
|
$status = $db->delete($this->table);
|
||||||
|
|
||||||
if ($status) {
|
if ($status) {
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ if (isset($_COOKIE['series_id']) && isset($_COOKIE['remember_token']))
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Login - Qrcode Generator</title>
|
<title>Login - QRForge</title>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
|
|
||||||
<body class="login-page" style="min-height: 512.391px;">
|
<body class="login-page" style="min-height: 512.391px;">
|
||||||
<div class="login-box">
|
<div class="login-box">
|
||||||
<div class="login-logo">
|
<div class="login-logo">
|
||||||
<img src="dist/img/DynamicQRCode_Original.png" style="width: 95%; height: 95%">
|
<img src="dist/img/brand/logo.svg" alt="QRForge" style="max-width: 260px;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "Qrcode Generator",
|
"name": "QRForge",
|
||||||
"short_name": "QRcode",
|
"short_name": "QRForge",
|
||||||
"description": "Self-hosted static and dynamic qr code generator",
|
"description": "Self-hosted static and dynamic qr code generator",
|
||||||
"start_url": "index.php",
|
"start_url": "index.php",
|
||||||
"scope": "./",
|
"scope": "./",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#ffffff",
|
"background_color": "#ffffff",
|
||||||
"theme_color": "#007bff",
|
"theme_color": "#2563EB",
|
||||||
"icons": [
|
"icons": [
|
||||||
{ "src": "dist/img/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
{ "src": "dist/img/icon-192.png", "sizes": "192x192", "type": "image/png" },
|
||||||
{ "src": "dist/img/icon-512.png", "sizes": "512x512", "type": "image/png" }
|
{ "src": "dist/img/icon-512.png", "sizes": "512x512", "type": "image/png" }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ require_once BASE_PATH . '/includes/auth_validate.php';
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ if($_SERVER["REQUEST_METHOD"] === "POST" && !isset($_POST["edit"]) && !isset($_P
|
|||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ $total_pages = $db->totalPages;
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ if($_SERVER["REQUEST_METHOD"] === "POST" && !isset($_POST["edit"])) {
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ $total_pages = $db->totalPages;
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<title>Qrcode Generator</title>
|
<title>QRForge</title>
|
||||||
<head>
|
<head>
|
||||||
<?php include './includes/head.php'; ?>
|
<?php include './includes/head.php'; ?>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||