5 Commits

Author SHA1 Message Date
yann64 a400b7cc66 Release 1.0.4 — changelog + bump version dev 1.0.5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 07:17:51 +02:00
yann64 ed5cfcd275 Fix wizard : suppression totale des sous-processus exec() dans install()
- APP_KEY : généré directement en PHP (random_bytes) + écrit dans .env + propagé
  via config() et putenv() → évite le bug de pattern-matching de key:generate
  (la clé en mémoire ≠ clé dans le .env réécrit par writeEnv)
- DB_* + APP_KEY : putenv() écrase l'env OS hérité au boot (pgsql/temp-key) pour
  que tout sous-processus futur hérite des bonnes valeurs
- optimize supprimé de l'installation : config:cache re-boostrappe l'app via
  bootstrap/app.php dans un contexte où l'Encrypter peut lever MissingAppKeyException ;
  optimize:clear seul suffit — Laravel reconstruit ses caches à la première requête
- key:generate converti en Artisan::call() puis remplacé par génération PHP directe

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 07:17:32 +02:00
yann64 4110caa25a Release 1.0.3 — changelog + bump version dev 1.0.4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 23:03:14 +02:00
yann64 9225abc804 Fix wizard : migrations via Artisan::call() pour éviter l'héritage d'env pgsql
Cause racine : public/index.php charge le .env auto-créé (pgsql) et appelle
putenv('DB_CONNECTION=pgsql'). Les sous-processus exec() héritent cet env OS.
phpdotenv en mode immutable refuse d'écraser une variable déjà définie →
le nouveau .env mysql est ignoré, la migration tente une connexion pgsql.

Fix : reconfiguration de la connexion BDD en mémoire via config() + DB::purge()
puis exécution des migrations via Artisan::call() dans le processus courant.
Plus aucun subprocess pour les migrations → aucun héritage d'env parasite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 22:19:50 +02:00
yann64 56dbd8a0bf Setup : affichage du numéro de version dans l'assistant d'installation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 22:12:04 +02:00
4 changed files with 102 additions and 18 deletions
+23
View File
@@ -5,6 +5,29 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag
---
## [1.0.4] — 2026-06-05
### Corrigé
- **Assistant d'installation — APP_KEY vide après installation** : `key:generate` remplace `APP_KEY=<clé_en_mémoire>` par regex dans le `.env`. Mais `writeEnv()` écrit `APP_KEY=` (vide) alors que la clé en mémoire est celle de l'auto-création (clé temporaire) — le pattern ne matche pas, la clé reste vide. Correction : la clé est générée directement en PHP (`random_bytes`), écrite dans le `.env` sans regex, puis propagée en mémoire (`config(['app.key'])`) et dans l'env OS (`putenv`).
- **Assistant d'installation — `MissingAppKeyException` lors de l'optimisation** : `optimize` appelle en interne `config:cache`, qui re-boostrappe une seconde instance de l'application depuis `bootstrap/app.php`. Ce second boot passe par tous les ServiceProviders et peut résoudre l'Encrypter avant que la clé soit accessible, levant `MissingAppKeyException` et renvoyant une erreur 500. Correction : `optimize` est supprimé de la procédure d'installation ; seul `optimize:clear` est conservé pour purger tout cache résiduel. Laravel reconstruit ses caches paresseusement à la première requête.
- **Assistant d'installation — connexion PostgreSQL forcée après login (MySQL)** : `putenv()` n'était appelé que pour les variables `DB_*` mais pas pour `APP_KEY`. Correction : tous les `putenv()` (dont `APP_KEY`) sont regroupés en un bloc cohérent, garantissant que tout sous-processus futur hérite des valeurs correctes.
---
## [1.0.3] — 2026-06-04
### Ajouté
- **Numéro de version dans l'assistant d'installation** — affiché sous le titre « Assistant d'installation » dans le layout du wizard (lu depuis le fichier `VERSION`)
### Corrigé
- **Assistant d'installation — conflit pgsql/mysql (cause racine)** : lors d'un démarrage sur serveur vierge, `public/index.php` auto-crée un `.env` depuis `.env.example` (driver `pgsql`) et Laravel charge cet env via `putenv()` au niveau OS. Les sous-processus `exec()` héritent cet env ; `phpdotenv` en mode immutable refuse d'écraser une variable déjà présente dans l'env OS → le `.env` réécrit avec `DB_CONNECTION=mysql` par le wizard était ignoré par le subprocess de migration, qui tentait une connexion PostgreSQL. Correction : les migrations sont maintenant exécutées via `Artisan::call()` dans le processus courant, après reconfiguration explicite en mémoire (`config(['database.default' => ...]`) + `DB::purge()` — aucun héritage d'env parasite.
- **`.htaccess`** — suppression des directives `php_flag display_errors on` ajoutées temporairement pour déboguer l'erreur 500 sur hébergement mutualisé.
---
## [1.0.2] — 2026-06-04
### Corrigé
+1 -1
View File
@@ -1 +1 @@
1.0.3
1.0.5
+70 -16
View File
@@ -3,6 +3,8 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use PDO;
use PDOException;
@@ -126,8 +128,6 @@ class SetupController extends Controller
$steps = [];
$success = true;
$php = $this->phpBinary();
$artisan = $php . ' ' . escapeshellarg(base_path('artisan'));
// 1. Écriture du .env
try {
@@ -138,24 +138,74 @@ class SetupController extends Controller
$success = false;
}
// 2. Génération de la clé APP_KEY
// 2. Génération de la clé APP_KEY — directement en PHP, sans passer par key:generate.
//
// Artisan key:generate remplace APP_KEY=<clé_en_mémoire> dans le .env grâce à un
// pattern regex. Mais writeEnv() vient d'écrire APP_KEY= (vide) alors qu'en mémoire
// la clé est celle de l'auto-création (TEMP_KEY) → le pattern ne matche pas → la
// clé reste vide dans le .env et la config:cache en hérite.
// Solution : générer la clé nous-mêmes, l'écrire directement dans le .env, et la
// propager en mémoire + env OS dès maintenant.
$appKey = null;
if ($success) {
[$ok, $out] = $this->artisanRun($artisan, 'key:generate --force');
$steps[] = ['ok' => $ok, 'label' => 'Génération de la clé de chiffrement (APP_KEY)', 'error' => $ok ? null : $out];
if (! $ok) $success = false;
try {
$appKey = 'base64:' . base64_encode(random_bytes(32));
$envPath = base_path('.env');
$env = file_get_contents($envPath);
$env = preg_replace('/^APP_KEY=.*/m', 'APP_KEY=' . $appKey, $env);
file_put_contents($envPath, $env);
config(['app.key' => $appKey]);
$steps[] = ['ok' => true, 'label' => 'Génération de la clé de chiffrement (APP_KEY)'];
} catch (\Exception $e) {
$steps[] = ['ok' => false, 'label' => 'Génération de la clé de chiffrement (APP_KEY)', 'error' => $e->getMessage()];
$success = false;
}
}
// 2b. Purge du cache de config pour forcer la lecture du nouveau .env
// (un bootstrap/cache/config.php résiduel sinon l'emporte sur le .env réécrit)
// 2b. Reconfiguration de la connexion BDD — processus courant ET sous-processus.
//
// putenv() écrase l'env OS hérité au boot (pgsql + TEMP_KEY) pour que tous les
// sous-processus futurs (config:cache interne à optimize…) reçoivent les bonnes
// valeurs. config() + DB::purge() reconfigure le processus courant en mémoire.
if ($success) {
$this->artisanRun($artisan, 'config:clear');
putenv("APP_KEY={$appKey}");
putenv("DB_CONNECTION={$dbData['driver']}");
putenv("DB_HOST={$dbData['host']}");
putenv("DB_PORT={$dbData['port']}");
putenv("DB_DATABASE={$dbData['database']}");
putenv("DB_USERNAME={$dbData['username']}");
putenv('DB_PASSWORD=' . ($dbData['password'] ?? ''));
$connConfig = $dbData['driver'] === 'pgsql'
? ['driver' => 'pgsql', 'host' => $dbData['host'], 'port' => (int) $dbData['port'],
'database' => $dbData['database'], 'username' => $dbData['username'],
'password' => $dbData['password'] ?? '', 'charset' => 'utf8', 'prefix' => '',
'schema' => 'public', 'sslmode' => 'prefer']
: ['driver' => 'mysql', 'host' => $dbData['host'], 'port' => (int) $dbData['port'],
'database' => $dbData['database'], 'username' => $dbData['username'],
'password' => $dbData['password'] ?? '', 'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true];
config([
'database.default' => $dbData['driver'],
"database.connections.{$dbData['driver']}" => $connConfig,
]);
DB::purge($dbData['driver']);
}
// 3. Migrations
// 3. Migrations (dans le processus courant, config BDD déjà écrasée ci-dessus)
if ($success) {
[$ok, $out] = $this->artisanRun($artisan, 'migrate --force');
$steps[] = ['ok' => $ok, 'label' => 'Migration de la base de données', 'error' => $ok ? null : $out];
if (! $ok) $success = false;
try {
$exitCode = Artisan::call('migrate', ['--force' => true]);
$out = trim(Artisan::output());
$ok = $exitCode === 0;
$steps[] = ['ok' => $ok, 'label' => 'Migration de la base de données', 'error' => $ok ? null : $out];
if (! $ok) $success = false;
} catch (\Exception $e) {
$steps[] = ['ok' => false, 'label' => 'Migration de la base de données', 'error' => $e->getMessage()];
$success = false;
}
}
// 4. Création du compte administrateur
@@ -182,10 +232,14 @@ class SetupController extends Controller
}
}
// 6. Optimisation des caches
// 6. Nettoyage des caches
// optimize:clear supprime tout cache résiduel (config, routes, vues, events).
// On n'appelle PAS optimize : config:cache re-boostrappe l'app depuis bootstrap/app.php
// dans un contexte qui peut ne pas avoir accès à notre APP_KEY via putenv, ce qui
// provoque MissingAppKeyException. Laravel reconstruit ses caches à la première
// requête — pas besoin de les préchauffer pendant l'installation.
if ($success) {
$this->artisanRun($artisan, 'optimize:clear');
$this->artisanRun($artisan, 'optimize');
Artisan::call('optimize:clear');
}
// 7. Marquage installation
+8 -1
View File
@@ -16,7 +16,14 @@
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-blue-600 text-white text-2xl font-bold mb-3 select-none">M</div>
<h1 class="text-2xl font-bold text-slate-800">MesRelevés</h1>
<p class="text-slate-500 text-sm mt-1">Assistant d'installation</p>
<p class="text-slate-500 text-sm mt-1">
Assistant d'installation
@php $version = trim(@file_get_contents(base_path('VERSION')) ?: ''); @endphp
@if($version)
<span class="mx-1.5 text-slate-300">·</span>
<span class="font-mono text-slate-400">v{{ $version }}</span>
@endif
</p>
</div>
{{-- Indicateur d'étapes --}}