Bir Laravel paketi geliştirdiniz. Bu paket, bir uygulamanın yapılandırmasını – .env dosyası ve veritabanında şifrelenmiş olarak saklanan ayarları – tek bir şifre korumalı ZIP dosyası olarak yedeklemeyi sağlayacak. Bu paketin en büyük avantajı taşınabilirlik: A sunucusundaki bir yedeği B sunucusuna geri yükleyebilirsiniz, hatta iki sunucunun farklı APP_KEY değerleri olsa bile. Ancak, geri yükleme sırasında anahtarı değiştiren bir test yazdığınızda, bu test başarısız oluyor. Veritabanı ayarları bozulmuş bir şekilde geri geliyor.
<p>Hatanın şifrelemede değil, orada unuttuğum bir önbellekte olduğunu fark ettim. Bugün <a href="https://github.com/cleaniquecoders/laravel-config-backup" target="_blank" rel="noopener noreferrer">laravel-config-backup</a> paketinin 1.1.0 sürümünü yayınladım ve bu taşınabilirlik düzeltmesi öne çıkan özellik oldu. Şimdi bunu anlatmak istiyorum, çünkü alınan ders bu paketten çok daha geniş bir yelpazeye yayılıyor.</p>
<h2>
<a name="why-appkey-portability-is-even-a-thing" href="#why-appkey-portability-is-even-a-thing">
</a>
Neden APP_KEY taşınabilirliği önemli
</h2>
<p>Laravel, verileri <code>APP_KEY</code> ile şifreler. Şifrelenmiş Eloquent cast’leri, imzalanmış çerezler, oturumlar - bunların hepsi bu değerden faydalanır. Eğer bir tabloyu <code>mysqldump</code> ile şifrelenmiş sütunlarla dump edip başka bir sunucuya yüklemeyi denerseniz, her şifrelenmiş sütun artık, yeni anahtarın çözemeyeceği bir ciphertext olur. Tamamen bozuk veri elde edersiniz.</p>
<p>Paketin kullandığı yöntem, arşiv içeriğini <strong>şifresiz</strong> olarak saklamaktır. Veritabanını dışa aktardığımda, satırlar <em>cast’leri aracılığıyla</em> çıkar, böylece şifrelenmiş bir sütun ZIP dosyası içinde düz bir değer haline gelir (ZIP dosyası ise AES-256 şifreli bir şifreyle korunmuş halde saklanır, yani düz metin olarak kalmaz). İçe aktarma sırasında, her satır modelden geri yazılır; bu da her verinin, hedefte aktif olan <code>APP_KEY</code> ile yeniden şifreleneceği anlamına gelir.</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>Server A (key A) Archive (decrypted) Server B (key B)──────────────── ─────────────────── ────────────────
settings.payload ──decrypt──▶ “Portable” ──import──▶ settings.payload
(ciphertext A) (cast) (cast) (ciphertext B)
<p>Bunu, mobilya gönderiminde olduğu gibi düşünün: montajlı bir dolabı, sığmadığı bir kapıdan geçiremezsiniz; parçalarını düz paketleyerek taşırsınız ve varış noktasında mevcut vidalarla yeniden monte edersiniz.</p>
<h2>
<a name="the-restore-sequence" href="#the-restore-sequence">
</a>
Geri Yükleme Sırası
</h2>
<p>Yeni bir <code>.env</code> dosyasıyla yapılan geri yükleme, <em>sipariş</em> konusunda dikkatli olmalıdır. Gerçek akış şu şekildedir:</p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code><span class="k">public</span> <span class="k">function</span> <span class="n">restore</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$absZipPath</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$password</span><span class="p">,</span> <span class="kt">array</span> <span class="nv">$sections</span><span class="p">,</span> <span class="kt">int</span><span class="o">|</span><span class="n">string</span><span class="o">|</span><span class="kc">null</span> <span class="nv">$userId</span> <span class="o">=</span> <span class="kc">null</span><span class="p">):</span> <span class="kt">array</span>{
// 1. Şu anki yapılandırmanın güvenli bir anlık görüntüsünü alıyoruz.
$safety = $this->create(
ConfigBackupSection::values(),
$password,
‘Otomatik ön geri yükleme güvenlik yedeği’,
$userId,
isSafety: true,
);
<span class="nv">$zip</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">openArchive</span><span class="p">(</span><span class="nv">$absZipPath</span><span class="p">,</span> <span class="nv">$password</span><span class="p">);</span> <span class="c1">// şifreyi doğrular</span>
<span class="nv">$appKeyChanged</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="c1">// 2. Önce .env dosyasını geri yükle. Eğer APP_KEY değişirse, aktif şifreleyici değiştirilmeli</span>
<span class="c1">// böylece sonraki DB yeniden şifreleme işlemleri FİNAL anahtarını kullanır.</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="nf">wants</span><span class="p">(</span><span class="nv">$sections</span><span class="p">,</span> <span class="nc">ConfigBackupSection</span><span class="o">::</span><span class="no">ENV</span><span class="p">)</span> <span class="o">&&</span> <span class="cm">/* ... */</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$oldKey</span> <span class="o">=</span> <span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="nf">config</span><span class="p">(</span><span class="s1">'app.key'</span><span class="p">);</span>
<span class="nc">File</span><span class="o">::</span><span class="nf">put</span><span class="p">(</span><span class="nf">base_path</span><span class="p">(</span><span class="s1">'.env'</span><span class="p">),</span> <span class="nv">$newEnv</span><span class="p">);</span>
<span class="nv">$newKey</span> <span class="o">=</span> <span class="nc">Env</span><span class="o">::</span><span class="nf">parse</span><span class="p">(</span><span class="nv">$newEnv</span><span class="p">)[</span><span class="s1">'APP_KEY'</span><span class="p">]</span> <span class="o">??</span> <span class="nv">$oldKey</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$newKey</span> <span class="o">!==</span> <span class="s1">''</span> <span class="o">&&</span> <span class="nv">$newKey</span> <span class="o">!==</span> <span class="nv">$oldKey</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">useEncryptionKey</span><span class="p">(</span><span class="nv">$newKey</span><span class="p">);</span>
<span class="nv">$appKeyChanged</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// 3. DB ayarlarını geri yükle — şimdi aktif anahtar ile yeniden şifrelenmiş olarak.</span>
<span class="c1">// ...</span>
<span class="nc">ConfigRestored</span><span class="o">::</span><span class="nf">dispatch</span><span class="p">(</span><span class="nv">$restored</span><span class="p">,</span> <span class="nv">$databaseSummary</span><span class="p">,</span> <span class="nv">$appKeyChanged</span><span class="p">,</span> <span class="nv">$safety</span><span class="o">-></span><span class="n">uuid</span><span class="p">);</span>
<span class="k">return</span> <span class="p">[</span>
<span class="s1">'safety_backup'</span> <span class="o">=></span> <span class="nv">$safety</span><span class="o">-></span><span class="n">uuid</span><span class="p">,</span>
<span class="s1">'restored'</span> <span class="o">=></span> <span class="nv">$restored</span><span class="p">,</span>
<span class="s1">'database'</span> <span class="o">=></span> <span class="nv">$databaseSummary</span><span class="p">,</span>
<span class="s1">'app_key_changed'</span> <span class="o">=></span> <span class="nv">$appKeyChanged</span><span class="p">,</span>
<span class="p">];</span>}


