Wizbrand is multitent DAM application using we an create multiple org and orgs, Dam assets, Now We want to add feature of Image manager in DAM and opted for Piwigo which is open source and single tenant. Now I am trying to develope a solution where each org when they click on "Image Manager" Piwigo installer should trigger and install 1 instance of Piwigo for each org, If Org is already having Piwigo instance, it should avoid installing new one and installed Piwigo should be accessible instead.

WIzbrand is developed in Laravel and PHP and Piwigo too in in PHP>

So overall requirement is, Then moment org admin click on "Image Manager", one Piwigo instance should be installed or existing installed Piwigo should be accessible.>>

Now What is the approach? Suggest me Design and Workflow of this project and how o should start coding for the same?

Design and Workflow for Integrating Piwigo as Multi-Tenant Image Manager in Wizbrand

Your requirement involves dynamically provisioning Piwigo instances per organization in Wizbrand, which is a multi-tenant Digital Asset Management (DAM) system built in Laravel and PHP. Since Piwigo is single-tenant, each organization should have a separate Piwigo instance.


Proposed Approach

  1. Database Integration: Maintain a table in Laravel to track which organization has a Piwigo instance.
  2. Automated Installation & Setup: If an organization clicks on Image Manager, the system checks if an instance is installed.
    • If not installed, trigger automatic Piwigo installation.
    • If already installed, redirect the org admin to their instance.
  3. Multi-Tenant Architecture via Subdomains/Path-based Access: Each Piwigo instance can be accessed using:
    • Subdomain: org1.wizbrand.com/piwigo/
    • Path-based: wizbrand.com/org1/piwigo/
  4. Authentication via SSO: Auto-login the Wizbrand admin to Piwigo using Laravel Authentication (Single Sign-On).
  5. Storage & Isolation: Store Piwigo instances in isolated directories for security and performance.
  6. Automated Cleanup: When an org is deleted, remove its corresponding Piwigo instance.

Step-by-Step Design and Workflow

Step 1: Database Design (Tracking Instances)

Create a piwigo_instances table in Laravel:

Schema::create('piwigo_instances', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('org_id');
    $table->string('piwigo_url');  // Store URL where Piwigo is installed
    $table->string('install_path'); // Path where Piwigo is installed
    $table->timestamps();

    $table->foreign('org_id')->references('id')->on('organizations')->onDelete('cascade');
});

Step 2: Installation Check and Trigger

When an organization admin clicks "Image Manager", check if a Piwigo instance exists.

public function handleImageManager($org_id)
{
    $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

    if ($piwigo) {
        return redirect($piwigo->piwigo_url); // Redirect if already installed
    }

    return $this->installPiwigo($org_id);
}

Step 3: Install Piwigo Dynamically

If the organization does not have Piwigo installed, trigger automated Piwigo installation.

public function installPiwigo($org_id)
{
    $org = Organization::find($org_id);
    $install_path = "/var/www/html/wizbrand/piwigo_" . $org->slug;
    $piwigo_url = "https://wizbrand.com/" . $org->slug . "/piwigo/";

    if (!file_exists($install_path)) {
        exec("cp -r /var/www/html/piwigo-template $install_path"); // Copy base template
        exec("chmod -R 777 $install_path"); // Adjust permissions

        // Create database for this Piwigo instance
        $db_name = "piwigo_" . $org->slug;
        DB::statement("CREATE DATABASE $db_name");

        // Set up Piwigo config file
        file_put_contents("$install_path/local/config/database.inc.php", "
        <?php
        \$conf['db_host'] = 'localhost';
        \$conf['db_user'] = 'piwigo_user';
        \$conf['db_password'] = 'piwigo_password';
        \$conf['db_name'] = '$db_name';
        ?>");

        // Run Piwigo installation script
        exec("php $install_path/install.php --admin-user=admin --admin-password=admin123 --admin-email=admin@$org->slug.com");

        // Save the instance record
        PiwigoInstance::create([
            'org_id' => $org_id,
            'piwigo_url' => $piwigo_url,
            'install_path' => $install_path
        ]);
    }

    return redirect($piwigo_url); // Redirect to the newly installed Piwigo instance
}

Step 4: Handling Authentication (SSO)

To ensure a smooth experience, implement Single Sign-On (SSO) for automatic login from Wizbrand to Piwigo.

Laravel JWT Authentication Token

  • When the org admin clicks "Image Manager," generate a JWT token and pass it to Piwigo.
public function generatePiwigoSSOToken($org_id, $user)
{
    $token = JWTAuth::fromUser($user, ['org_id' => $org_id]);
    return redirect($this->getPiwigoUrl($org_id) . "?token=$token");
}

Modify Piwigo to Accept Laravel JWT Token

  • Create a PHP script in Piwigo that accepts the token, verifies it using Laravel's secret key, and logs in the user.
require 'vendor/autoload.php';
use Firebase\JWT\JWT;

$token = $_GET['token'];
$secretKey = "laravel_secret_key";

try {
    $decoded = JWT::decode($token, $secretKey, ['HS256']);
    $user_id = $decoded->user_id;
    
    // Log in the user automatically in Piwigo
    $_SESSION['auth'] = true;
    $_SESSION['user_id'] = $user_id;

    header("Location: gallery.php");
} catch (Exception $e) {
    die("Invalid token");
}

Step 5: Accessing Existing Piwigo Instances

Modify your handleImageManager() function to check if an org already has an instance.

public function handleImageManager($org_id)
{
    $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

    if ($piwigo) {
        return $this->generatePiwigoSSOToken($org_id, auth()->user()); // Redirect with SSO login
    }

    return $this->installPiwigo($org_id);
}

Step 6: Cleanup and Deletion

When an organization is deleted, remove the associated Piwigo instance.

public function deletePiwigoInstance($org_id)
{
    $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

    if ($piwigo) {
        exec("rm -rf " . $piwigo->install_path); // Delete files
        DB::statement("DROP DATABASE piwigo_" . $org_id); // Drop the database
        $piwigo->delete();
    }
}

Tech Stack Required

  • Laravel (Wizbrand) → Backend for managing Piwigo installation.
  • MySQL → Database for tracking installed instances.
  • JWT Authentication → Seamless SSO for Piwigo.
  • Shell Commands (exec) → Automate Piwigo installation.
  • Apache/Nginx → Webserver configuration for multi-instance Piwigo.

Summary of Workflow

  1. User clicks "Image Manager" in Wizbrand.
  2. Check if Piwigo instance exists:
    • If yes, redirect to the instance with SSO authentication.
    • If no, trigger automated Piwigo installation.
  3. Automate Installation:
    • Copy Piwigo files to org-specific folder.
    • Set up a new database for the instance.
    • Configure database connection.
    • Complete Piwigo setup via CLI.
  4. Ensure seamless login via JWT SSO.
  5. Handle deletion of Piwigo instances when an org is removed.

Next Steps to Start Coding

  1. Setup Piwigo Base Template: Prepare a ready-to-use Piwigo folder.
  2. Create Laravel Model & Migration (PiwigoInstance) to store instances.
  3. Develop Installer Script to deploy Piwigo dynamically.
  4. Implement SSO via JWT Authentication.
  5. Write Cleanup Script to remove Piwigo when an org is deleted.
  6. Test with multiple organizations and ensure seamless switching.

This approach ensures scalability, automation, and security, making it ideal for integrating Piwigo with Wizbrand.


Here's the complete Laravel Controller to handle Piwigo multi-instance installation and authentication in Wizbrand. This controller manages:

  • Checking existing Piwigo instances
  • Installing Piwigo dynamically for each organization
  • SSO Authentication using JWT
  • Cleaning up instances when organizations are removed

File: app/Http/Controllers/PiwigoController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Models\PiwigoInstance;
use App\Models\Organization;
use Tymon\JWTAuth\Facades\JWTAuth;

class PiwigoController extends Controller
{
    protected $piwigo_base_path = "/var/www/html/wizbrand/piwigo_";
    protected $piwigo_template_path = "/var/www/html/piwigo-template";
    protected $piwigo_base_url = "https://wizbrand.com/";

    /**
     * Handle Image Manager request for an organization.
     * Install Piwigo if not exists or redirect to existing instance.
     */
    public function handleImageManager($org_id)
    {
        $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

        if ($piwigo) {
            return $this->generatePiwigoSSOToken($org_id, Auth::user());
        }

        return $this->installPiwigo($org_id);
    }

    /**
     * Install a new Piwigo instance for an organization.
     */
    public function installPiwigo($org_id)
    {
        $org = Organization::findOrFail($org_id);
        $install_path = $this->piwigo_base_path . $org->slug;
        $piwigo_url = $this->piwigo_base_url . $org->slug . "/piwigo/";

        if (!file_exists($install_path)) {
            // Copy Piwigo template to new location
            exec("cp -r $this->piwigo_template_path $install_path");
            exec("chmod -R 777 $install_path");

            // Create database for Piwigo instance
            $db_name = "piwigo_" . $org->slug;
            DB::statement("CREATE DATABASE $db_name");
            
            // Configure database connection
            file_put_contents("$install_path/local/config/database.inc.php", "
            <?php
            \$conf['db_host'] = 'localhost';
            \$conf['db_user'] = 'piwigo_user';
            \$conf['db_password'] = 'piwigo_password';
            \$conf['db_name'] = '$db_name';
            ?>");

            // Run Piwigo Installation
            exec("php $install_path/install.php --admin-user=admin --admin-password=admin123 --admin-email=admin@$org->slug.com");

            // Store in database
            PiwigoInstance::create([
                'org_id' => $org_id,
                'piwigo_url' => $piwigo_url,
                'install_path' => $install_path
            ]);
        }

        return redirect($piwigo_url);
    }

    /**
     * Generate SSO JWT token and redirect user to their Piwigo instance.
     */
    public function generatePiwigoSSOToken($org_id, $user)
    {
        $token = JWTAuth::fromUser($user, ['org_id' => $org_id]);
        $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

        if ($piwigo) {
            return redirect($piwigo->piwigo_url . "?token=$token");
        }

        return redirect()->back()->with('error', 'Piwigo instance not found.');
    }

    /**
     * Delete a Piwigo instance when an organization is removed.
     */
    public function deletePiwigoInstance($org_id)
    {
        $piwigo = PiwigoInstance::where('org_id', $org_id)->first();

        if ($piwigo) {
            exec("rm -rf " . $piwigo->install_path);
            DB::statement("DROP DATABASE piwigo_" . $org_id);
            $piwigo->delete();
        }

        return response()->json(['message' => 'Piwigo instance deleted successfully.']);
    }
}

Database Migration for piwigo_instances Table

Create a migration file for tracking Piwigo instances.

php artisan make:migration create_piwigo_instances_table --create=piwigo_instances

Modify the generated file:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePiwigoInstancesTable extends Migration
{
    public function up()
    {
        Schema::create('piwigo_instances', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('org_id');
            $table->string('piwigo_url');
            $table->string('install_path');
            $table->timestamps();

            $table->foreign('org_id')->references('id')->on('organizations')->onDelete('cascade');
        });
    }

    public function down()
    {
        Schema::dropIfExists('piwigo_instances');
    }
}

Run the migration:

php artisan migrate

Modifying Piwigo to Accept JWT SSO

Create a script inside each Piwigo instance to handle JWT authentication.

File: local/sso_auth.php

<?php
require 'vendor/autoload.php';
use Firebase\JWT\JWT;

$token = $_GET['token'];
$secretKey = "laravel_secret_key";

try {
    $decoded = JWT::decode($token, $secretKey, ['HS256']);
    $user_id = $decoded->sub;

    $_SESSION['auth'] = true;
    $_SESSION['user_id'] = $user_id;

    header("Location: gallery.php");
} catch (Exception $e) {
    die("Invalid token");
}

Routes (routes/web.php)

Define routes to manage Piwigo instances.

use App\Http\Controllers\PiwigoController;

Route::get('/image-manager/{org_id}', [PiwigoController::class, 'handleImageManager']);
Route::delete('/image-manager/delete/{org_id}', [PiwigoController::class, 'deletePiwigoInstance']);

Testing

  1. Navigate to Image Manager:

    • URL: https://wizbrand.com/image-manager/1
    • If instance exists → Redirect to Piwigo.
    • If not → Install Piwigo & Redirect.
  2. Delete an Instance:

    • Run: DELETE https://wizbrand.com/image-manager/delete/1

Key Features in This Controller

✅ Checks existing Piwigo instance before installation
✅ Automatically installs a new Piwigo instance per organization
✅ Sets up a unique database per Piwigo instance
✅ Redirects existing users to their Piwigo instance
✅ Implements JWT-based SSO authentication
✅ Deletes Piwigo instances when organizations are removed


Next Steps

  1. Test installation automation for multiple orgs 🚀
  2. Optimize permissions for security 🔐
  3. Enhance logging & monitoring 📊

Would you like me to add a command-line tool (artisan command) to install Piwigo manually? 🚀