用開源軟件製作 QR CODE 生成網頁

大家應該很多時都會用到 QR CODE 有些網頁要付費才能用,有些免費但有些廣告彈出,今次我就介紹如何用開源軟件製作自 QR 產生器。

我們使用 chillerlan/php-qrcode 庫, Apache, php 軟件

For the QR Code reader, either ext-gd or ext-imagick is required!

chillerlan/php-qrcode 用 composer 安裝

開工

先安裝好 linux 系統我用 ubutu 作演示 , 如果你沒有獨立的 linux server , 可以在 windows 裝 vritualbox , 作測試之用 又或者買 raspberry pi, orange pi 等等做一做 mini server .

# 先安裝 apache web server
apt install apache2

# 再安裝 composer 
apt install composer 

php 要求8.4+ , ubuntu 官方 php package 是 8.3 , 所以用另一方法安裝其他版本的 php

# 先 update package source
sudo apt update

# 再 Add PHP Repository 
sudo apt install software-properties-common gnupg2  apt-transport-https lsb-release ca-certificates

sudo add-apt-repository ppa:ondrej/php

# 安裝 php8.4 
sudo apt install php8.4 php8.4-cli php8.4-gd php8.4-imagick php8.4-zip php8.4-xml php8.4-common php8.4-mbstring

# apache2 啟用 php8.4
a2enmod php8.4

安裝 chillerlan/php-qrcode

# 在你的 home 建立新 folder 把 php-qrcode 下載到該 folder 

cd ~
mkdir temp 
cd temp
composer require chillerlan/php-qrcode

這時 temp folder 內應該有 “vendor” folder 把這個 folder copy 到 “/var/www/html” 裏面 , 再把 index.php 製作出來, 就用 AI 生成吧 !

我用 deepseek 生成 index.php , 這個 file 包含 logo 拼合

<?php
require_once 'vendor/autoload.php';

use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use chillerlan\QRCode\Common\EccLevel;
use chillerlan\QRCode\Output\QRGdImagePNG;

$qrCodeBase64 = '';
$error = '';
$outputPath = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['text'])) {
    $text = trim($_POST['text']);
    
    if (empty($text)) {
        $error = '请输入要编码的文本或 URL。';
    } else {
        try {
            // 配置二维码选项 - 使用 QRGdImagePNG 输出类
            $options = new QROptions([
                'outputInterface'  => QRGdImagePNG::class,  // PNG 输出
                'eccLevel'         => EccLevel::H,          // 高纠错级别(加 Logo 必需)
                'version'          => 7,
                'scale'            => 10,
                'outputBase64'     => false,
                'imageTransparent' => true,
            ]);
            
            // 生成二维码
            $qrcode = new QRCode($options);
            $qrPngData = $qrcode->render($text);
            
            // 从二进制数据创建 GD 图像资源
            $qrImage = imagecreatefromstring($qrPngData);
            
            if (!$qrImage) {
                throw new Exception('无法创建二维码图像');
            }
            
            // 处理 Logo 上传
            if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
                $logoFile = $_FILES['logo']['tmp_name'];
                $logoInfo = getimagesize($logoFile);
                
                if ($logoInfo && in_array($logoInfo[2], [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_WEBP])) {
                    switch ($logoInfo[2]) {
                        case IMAGETYPE_PNG:
                            $logoImage = imagecreatefrompng($logoFile);
                            break;
                        case IMAGETYPE_JPEG:
                            $logoImage = imagecreatefromjpeg($logoFile);
                            break;
                        case IMAGETYPE_WEBP:
                            $logoImage = imagecreatefromwebp($logoFile);
                            break;
                        default:
                            $logoImage = null;
                    }
                    
                    if ($logoImage) {
                        $qrWidth = imagesx($qrImage);
                        $qrHeight = imagesy($qrImage);
                        $logoWidth = imagesx($logoImage);
                        $logoHeight = imagesy($logoImage);
                        
                        // Logo 占二维码的 20%
                        $logoMaxWidth = (int)($qrWidth / 5);
                        $logoMaxHeight = (int)($qrHeight / 5);
                        
                        $scale = min($logoMaxWidth / $logoWidth, $logoMaxHeight / $logoHeight, 1);
                        $newLogoWidth = max(1, (int)($logoWidth * $scale));
                        $newLogoHeight = max(1, (int)($logoHeight * $scale));
                        
                        $dstX = (int)(($qrWidth - $newLogoWidth) / 2);
                        $dstY = (int)(($qrHeight - $newLogoHeight) / 2);
                        
                        $resizedLogo = imagecreatetruecolor($newLogoWidth, $newLogoHeight);
                        imagealphablending($resizedLogo, false);
                        imagesavealpha($resizedLogo, true);
                        $transparent = imagecolorallocatealpha($resizedLogo, 0, 0, 0, 127);
                        imagefilledrectangle($resizedLogo, 0, 0, $newLogoWidth, $newLogoHeight, $transparent);
                        
                        imagecopyresampled($resizedLogo, $logoImage, 0, 0, 0, 0, 
                                          $newLogoWidth, $newLogoHeight, $logoWidth, $logoHeight);
                        
                        imagealphablending($qrImage, true);
                        imagecopy($qrImage, $resizedLogo, $dstX, $dstY, 0, 0, 
                                 $newLogoWidth, $newLogoHeight);
                        
                        imagedestroy($logoImage);
                        imagedestroy($resizedLogo);
                    }
                }
            }
            
            // 转为 Base64 显示
            ob_start();
            imagepng($qrImage);
            $qrPngData = ob_get_clean();
            $qrCodeBase64 = 'data:image/png;base64,' . base64_encode($qrPngData);
            
            // 保存文件
            if (!is_dir('qrcodes')) {
                mkdir('qrcodes', 0777, true);
            }
            $outputPath = 'qrcodes/qr_' . time() . '.png';
            imagepng($qrImage, $outputPath);
            
            imagedestroy($qrImage);
            
        } catch (Exception $e) {
            $error = '生成二维码失败:' . $e->getMessage();
        }
    }
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>带 Logo 的二维码生成器</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            max-width: 700px;
            margin: 0 auto;
            background: white;
            border-radius: 20px;
            padding: 40px;
        }
        h1 { text-align: center; margin-bottom: 30px; color: #333; }
        .form-group { margin-bottom: 20px; }
        label { display: block; margin-bottom: 8px; font-weight: 500; color: #555; }
        textarea, input[type="file"] {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 14px;
        }
        textarea:focus, input:focus { outline: none; border-color: #667eea; }
        button {
            width: 100%;
            padding: 12px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 10px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
        }
        button:hover { transform: translateY(-2px); }
        .result { text-align: center; margin-top: 30px; }
        .qr-container { margin: 20px 0; }
        .qr-container img { max-width: 100%; border-radius: 10px; }
        .download-link {
            display: inline-block;
            padding: 10px 20px;
            background: #4CAF50;
            color: white;
            text-decoration: none;
            border-radius: 8px;
        }
        .error { background: #fee; color: #c33; padding: 10px; border-radius: 8px; margin-top: 20px; }
        .tip { background: #e8f0fe; padding: 10px; border-radius: 8px; margin-top: 15px; font-size: 13px; }
    </style>
</head>
<body>
    <div class="container">
        <h1>📱 带 Logo 的二维码生成器</h1>
        
        <form method="POST" enctype="multipart/form-data">
            <div class="form-group">
                <label>文本或 URL:</label>
                <textarea name="text" rows="3" placeholder="https://github.com"></textarea>
            </div>
            <div class="form-group">
                <label>Logo 图片(可选):</label>
                <input type="file" name="logo" accept="image/png,image/jpeg,image/webp">
            </div>
            <button type="submit">✨ 生成二维码</button>
        </form>
        
        <?php if ($error): ?>
            <div class="error">⚠️ <?php echo htmlspecialchars($error); ?></div>
        <?php endif; ?>
        
        <?php if ($qrCodeBase64): ?>
            <div class="result">
                <div class="qr-container">
                    <img src="<?php echo $qrCodeBase64; ?>" alt="QR Code">
                </div>
                <?php if ($outputPath): ?>
                    <a href="<?php echo $outputPath; ?>" download class="download-link">💾 下载 PNG</a>
                <?php endif; ?>
            </div>
        <?php endif; ?>
        
        <div class="tip">
            💡 提示:需要 PHP 8.2+ 和 GD 扩展。Logo 会自动居中缩放,建议使用透明背景 PNG。
        </div>
    </div>
</body>
</html>

如果順利的話 , 你開瀏覽器輸入你的 server ip

這是最基本應用 , 你還可以叫 deepseek 加上不同的內容 , 例如 : QR CODE 底色等等 …….