<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://sonsuzus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sonsuzus.github.io/" rel="alternate" type="text/html" /><updated>2026-08-06T11:46:47+00:00</updated><id>https://sonsuzus.github.io/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">Değişkenler ve Kontrol Akışıyla Dinamik Sayfalar Tasarlamak</title><link href="https://sonsuzus.github.io/posts/degiskenler-ve-kontrol-akisiyla-dinamik-sayfalar-tasarlamak/" rel="alternate" type="text/html" title="Değişkenler ve Kontrol Akışıyla Dinamik Sayfalar Tasarlamak" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/degiskenler-ve-kontrol-akisiyla-dinamik-sayfalar-tasarlamak</id><content type="html" xml:base="https://sonsuzus.github.io/posts/degiskenler-ve-kontrol-akisiyla-dinamik-sayfalar-tasarlamak/"><![CDATA[<p>Bir web sayfasının kullanıcıya göre farklı davranmasını sağlayan temel güç, değişkenler ve kontrol akış yapılarından gelir. Değişkenler verileri hafızada tutarken <code class="language-plaintext highlighter-rouge">if-else</code> ve <code class="language-plaintext highlighter-rouge">switch-case</code> gibi yapılar programın hangi kod yolunu izleyeceğine karar verir. Kısacası değişkenler sahnedeki oyuncuları, kontrol yapıları ise senaryoyu temsil eder.</p>

<p>``</p>

<h2 id="değişkenler-neden-gereklidir">Değişkenler Neden Gereklidir?</h2>

<p>Değişken, bir değeri program çalışırken saklayabilmek ve daha sonra kullanabilmek için verilen isimdir. Kullanıcının adı, ürün fiyatı, oturum durumu veya sepetteki ürün sayısı birer değişkende tutulabilir.</p>

<p>JavaScript’te modern değişken tanımlama işlemleri genellikle <code class="language-plaintext highlighter-rouge">let</code> ve <code class="language-plaintext highlighter-rouge">const</code> ile gerçekleştirilir:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">kullaniciAdi</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">Ada</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">sepetAdedi</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">oturumAcik</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>

<span class="nx">sepetAdedi</span> <span class="o">=</span> <span class="nx">sepetAdedi</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">kullaniciAdi</span><span class="p">}</span><span class="s2"> kullanıcısının sepetinde </span><span class="p">${</span><span class="nx">sepetAdedi</span><span class="p">}</span><span class="s2"> ürün var.`</span><span class="p">);</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">const</code>, yeniden atanmayacak bir değişken oluşturur. <code class="language-plaintext highlighter-rouge">let</code> ise değeri sonradan değiştirilebilen veriler için kullanılır. Sepete yeni ürün eklendiğinde <code class="language-plaintext highlighter-rouge">sepetAdedi</code> güncellenebilir; ancak kullanıcının o işlem boyunca değişmeyen adı <code class="language-plaintext highlighter-rouge">const</code> ile tanımlanabilir.</p>

<table>
  <thead>
    <tr>
      <th>Anahtar kelime</th>
      <th style="text-align: right">Yeniden atanabilir mi?</th>
      <th>Kapsam</th>
      <th>Önerilen kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">const</code></td>
      <td style="text-align: right">Hayır</td>
      <td>Blok</td>
      <td>Varsayılan tercih</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">let</code></td>
      <td style="text-align: right">Evet</td>
      <td>Blok</td>
      <td>Değişecek değerler</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">var</code></td>
      <td style="text-align: right">Evet</td>
      <td>Fonksiyon</td>
      <td>Eski kodlarla uyumluluk</td>
    </tr>
  </tbody>
</table>

<p>Değişkenlerin hafızadaki davranışı veri türüne göre farklılaşabilir. Sayı ve boolean gibi ilkel değerler doğrudan değer mantığıyla kullanılırken nesneler referans üzerinden yönetilir. Bu nedenle bir nesneyi başka değişkene atamak her zaman bağımsız bir kopya üretmez.</p>

<h2 id="koşulların-matematiksel-mantığı">Koşulların Matematiksel Mantığı</h2>

<p>Kontrol akışının merkezinde sonucu <code class="language-plaintext highlighter-rouge">true</code> veya <code class="language-plaintext highlighter-rouge">false</code> olan ifadeler bulunur. Örneğin yaş değişkeni $y$ ise yetişkinlik koşulu $y \geq 18$ biçiminde gösterilebilir. İki şartın birlikte sağlanması gerekiyorsa mantıksal VE, alternatiflerden biri yeterliyse mantıksal VEYA kullanılır.</p>

<table>
  <thead>
    <tr>
      <th>Mantıksal işlem</th>
      <th>JavaScript</th>
      <th>Sonucun doğru olma durumu</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>VE</td>
      <td><code class="language-plaintext highlighter-rouge">A &amp;&amp; B</code></td>
      <td>İki koşul da doğruysa</td>
    </tr>
    <tr>
      <td>VEYA</td>
      <td><code class="language-plaintext highlighter-rouge">A \|\| B</code></td>
      <td>En az bir koşul doğruysa</td>
    </tr>
    <tr>
      <td>DEĞİL</td>
      <td><code class="language-plaintext highlighter-rouge">!A</code></td>
      <td>A yanlışsa</td>
    </tr>
  </tbody>
</table>

<h2 id="if-else-ile-sayfa-akışını-yönetmek"><code class="language-plaintext highlighter-rouge">if-else</code> ile Sayfa Akışını Yönetmek</h2>

<p><code class="language-plaintext highlighter-rouge">if-else</code>, farklı ve esnek koşulları değerlendirmek için idealdir. Bir üyelik sayfasının kullanıcı durumuna göre mesaj göstermesi şöyle sağlanabilir:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">yas</span> <span class="o">=</span> <span class="mi">22</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">oturumAcik</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>

<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">oturumAcik</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Lütfen önce giriş yapın.</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if </span><span class="p">(</span><span class="nx">yas</span> <span class="o">&gt;=</span> <span class="mi">18</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Yetişkin içerik alanına hoş geldiniz.</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Bu bölüm için yaşınız uygun değil.</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Program koşulları yukarıdan aşağıya değerlendirir ve doğru olan ilk bloğu çalıştırır. Bu nedenle daha özel koşulları üstte, genel koşulları altta konumlandırmak hatalı yönlendirmeleri önler.</p>

<h2 id="switch-case-ne-zaman-kullanılır"><code class="language-plaintext highlighter-rouge">switch-case</code> Ne Zaman Kullanılır?</h2>

<p>Tek bir değişkenin birçok sabit değerle karşılaştırıldığı durumlarda <code class="language-plaintext highlighter-rouge">switch-case</code> daha okunaklı olabilir. Örneğin kullanıcının rolüne göre panel seçilebilir:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">rol</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">editor</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">hedefSayfa</span><span class="p">;</span>

<span class="k">switch </span><span class="p">(</span><span class="nx">rol</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">case</span> <span class="dl">'</span><span class="s1">admin</span><span class="dl">'</span><span class="p">:</span>
    <span class="nx">hedefSayfa</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/yonetim</span><span class="dl">'</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">case</span> <span class="dl">'</span><span class="s1">editor</span><span class="dl">'</span><span class="p">:</span>
    <span class="nx">hedefSayfa</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/icerikler</span><span class="dl">'</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="k">case</span> <span class="dl">'</span><span class="s1">uye</span><span class="dl">'</span><span class="p">:</span>
    <span class="nx">hedefSayfa</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/profil</span><span class="dl">'</span><span class="p">;</span>
    <span class="k">break</span><span class="p">;</span>
  <span class="nl">default</span><span class="p">:</span>
    <span class="nx">hedefSayfa</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">/giris</span><span class="dl">'</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="s2">`Yönlendirilecek adres: </span><span class="p">${</span><span class="nx">hedefSayfa</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">break</code> kullanılmazsa program sonraki <code class="language-plaintext highlighter-rouge">case</code> bloklarına da geçebilir. Bazen bilinçli olarak kullanılan bu davranış, çoğu başlangıç hatasının da kaynağıdır. <code class="language-plaintext highlighter-rouge">default</code> ise hiçbir eşleşme bulunmadığında güvenli bir varsayılan yol sağlar.</p>

<h2 id="hangisini-seçmeliyiz">Hangisini Seçmeliyiz?</h2>

<p>Aralıklar, birleşik mantıksal ifadeler ve karmaşık kurallar için <code class="language-plaintext highlighter-rouge">if-else</code>; tek bir değerin belirli seçeneklerle eşleştirilmesi için <code class="language-plaintext highlighter-rouge">switch-case</code> tercih edilmelidir. Koşullar büyüdükçe karar mantığını küçük fonksiyonlara ayırmak kodun test edilmesini kolaylaştırır. Böylece sayfa akışı bir labirente değil, tabelaları düzgün yerleştirilmiş eğlenceli bir yolculuğa dönüşür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="değişkenler" /><category term="kontrol akışı" /><category term="javascript" /><summary type="html"><![CDATA[Bir web sayfasının kullanıcıya göre farklı davranmasını sağlayan temel güç, değişkenler ve kontrol akış yapılarından gelir. Değişkenler verileri hafızada tutarken if-else ve switch-case gibi yapılar programın hangi kod yolunu izleyeceğine karar verir. Kısacası değişkenler sahnedeki oyuncuları, kontrol yapıları ise senaryoyu temsil eder.]]></summary></entry><entry><title type="html">Döngüler ve Dizilerle Dinamik HTML Üretimi</title><link href="https://sonsuzus.github.io/posts/donguler-ve-dizilerle-dinamik-html-uretimi/" rel="alternate" type="text/html" title="Döngüler ve Dizilerle Dinamik HTML Üretimi" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/donguler-ve-dizilerle-dinamik-html-uretimi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/donguler-ve-dizilerle-dinamik-html-uretimi/"><![CDATA[<p>Bir web sayfasındaki ürün kartlarını tek tek elle yazmak, aynı şarkıyı yüz kez başa sarmaya benzer: yapılabilir ama hiç eğlenceli değildir. Diziler verileri düzenli biçimde saklarken <code class="language-plaintext highlighter-rouge">for</code> ve <code class="language-plaintext highlighter-rouge">foreach</code> döngüleri bu verileri sırayla işler. Böylece birkaç satırlık PHP koduyla onlarca HTML bloğunu dinamik, tutarlı ve kolay güncellenebilir biçimde ekrana basabiliriz.</p>

<p>``</p>

<h2 id="temel-mantık-veri-ayrı-görünüm-ayrı">Temel Mantık: Veri Ayrı, Görünüm Ayrı</h2>

<p>Dizi, birden fazla değeri tek değişken altında tutan veri yapısıdır. İndeksli dizilerde elemanlara <code class="language-plaintext highlighter-rouge">0</code>, <code class="language-plaintext highlighter-rouge">1</code>, <code class="language-plaintext highlighter-rouge">2</code> gibi konumlarla; ilişkisel dizilerde ise <code class="language-plaintext highlighter-rouge">ad</code>, <code class="language-plaintext highlighter-rouge">fiyat</code> veya <code class="language-plaintext highlighter-rouge">stok</code> gibi anlamlı anahtarlarla erişilir.</p>

<p>Bir dizide $n$ eleman varsa bütün elemanları bir kez ziyaret eden döngünün çalışma maliyeti yaklaşık olarak:</p>

\[T(n) = c \cdot n\]

<p>şeklinde ifade edilir. Buradaki $c$, her eleman için yapılan sabit miktardaki işlemdir. Bu nedenle temel listeleme işleminin zaman karmaşıklığı $O(n)$ olur. Eleman sayısı iki katına çıktığında yapılacak iş de yaklaşık iki katına çıkar.</p>

<table>
  <thead>
    <tr>
      <th>Yapı</th>
      <th>Kullanım biçimi</th>
      <th>En uygun olduğu durum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>İndeksli dizi</td>
      <td><code class="language-plaintext highlighter-rouge">$renkler[0]</code></td>
      <td>Basit ve sıralı değer listeleri</td>
    </tr>
    <tr>
      <td>İlişkisel dizi</td>
      <td><code class="language-plaintext highlighter-rouge">$urun['ad']</code></td>
      <td>Özellikleri bulunan kayıtlar</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">for</code></td>
      <td>Sayaç ve indeks kullanır</td>
      <td>Konum bilgisi gerektiğinde</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">foreach</code></td>
      <td>Elemanı doğrudan verir</td>
      <td>Koleksiyonları okunaklı biçimde dolaşırken</td>
    </tr>
  </tbody>
</table>

<h2 id="for-ile-sıralı-verileri-yazdırmak"><code class="language-plaintext highlighter-rouge">for</code> ile Sıralı Verileri Yazdırmak</h2>

<p><code class="language-plaintext highlighter-rouge">for</code> döngüsü başlangıç, koşul ve artış olmak üzere üç parçadan oluşur. Dizinin indeksine veya sıra numarasına ihtiyaç duyduğumuzda oldukça kullanışlıdır.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nv">$diller</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'PHP'</span><span class="p">,</span> <span class="s1">'JavaScript'</span><span class="p">,</span> <span class="s1">'Python'</span><span class="p">,</span> <span class="s1">'Go'</span><span class="p">];</span>

<span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nb">count</span><span class="p">(</span><span class="nv">$diller</span><span class="p">);</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">echo</span> <span class="s1">'&lt;p&gt;'</span> <span class="mf">.</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'. '</span> <span class="mf">.</span> <span class="nv">$diller</span><span class="p">[</span><span class="nv">$i</span><span class="p">]</span> <span class="mf">.</span> <span class="s1">'&lt;/p&gt;'</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">?&gt;</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">$i</code>, dizinin mevcut indeksini temsil eder. Diziler sıfırdan başladığı için kullanıcıya gösterilen sıra numarasında <code class="language-plaintext highlighter-rouge">$i + 1</code> kullanılır. Koşulun <code class="language-plaintext highlighter-rouge">$i &lt;= count($diller)</code> biçiminde yazılması, olmayan son elemana erişmeye çalışacağı için klasik bir “bir adım fazla” hatası üretir.</p>

<p>Dizi boyutu sık değişmiyorsa <code class="language-plaintext highlighter-rouge">count()</code> sonucunu önceden saklamak da mümkündür:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$toplam</span> <span class="o">=</span> <span class="nb">count</span><span class="p">(</span><span class="nv">$diller</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="nv">$i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nv">$i</span> <span class="o">&lt;</span> <span class="nv">$toplam</span><span class="p">;</span> <span class="nv">$i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">echo</span> <span class="s1">'&lt;li&gt;'</span> <span class="mf">.</span> <span class="nb">htmlspecialchars</span><span class="p">(</span><span class="nv">$diller</span><span class="p">[</span><span class="nv">$i</span><span class="p">])</span> <span class="mf">.</span> <span class="s1">'&lt;/li&gt;'</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">htmlspecialchars()</code> özel HTML karakterlerini dönüştürerek kullanıcı kaynaklı verilerin güvenli gösterilmesine yardımcı olur.</p>

<h2 id="foreach-ile-ürün-kartları-oluşturmak"><code class="language-plaintext highlighter-rouge">foreach</code> ile Ürün Kartları Oluşturmak</h2>

<p>İlişkisel ve çok boyutlu dizilerde <code class="language-plaintext highlighter-rouge">foreach</code>, indeks yönetme zahmetini ortadan kaldırır. Aşağıdaki veri kümesindeki her ürün bir ilişkisel dizidir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nv">$urunler</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">[</span><span class="s1">'ad'</span> <span class="o">=&gt;</span> <span class="s1">'Mekanik Klavye'</span><span class="p">,</span> <span class="s1">'fiyat'</span> <span class="o">=&gt;</span> <span class="mi">2450</span><span class="p">,</span> <span class="s1">'stok'</span> <span class="o">=&gt;</span> <span class="mi">8</span><span class="p">],</span>
    <span class="p">[</span><span class="s1">'ad'</span> <span class="o">=&gt;</span> <span class="s1">'Kablosuz Fare'</span><span class="p">,</span> <span class="s1">'fiyat'</span> <span class="o">=&gt;</span> <span class="mi">980</span><span class="p">,</span> <span class="s1">'stok'</span> <span class="o">=&gt;</span> <span class="mi">0</span><span class="p">],</span>
    <span class="p">[</span><span class="s1">'ad'</span> <span class="o">=&gt;</span> <span class="s1">'USB Mikrofon'</span><span class="p">,</span> <span class="s1">'fiyat'</span> <span class="o">=&gt;</span> <span class="mi">3150</span><span class="p">,</span> <span class="s1">'stok'</span> <span class="o">=&gt;</span> <span class="mi">4</span><span class="p">]</span>
<span class="p">];</span>
<span class="cp">?&gt;</span>

<span class="nt">&lt;section</span> <span class="na">class=</span><span class="s">"urun-listesi"</span><span class="nt">&gt;</span>
<span class="cp">&lt;?php</span> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$urunler</span> <span class="k">as</span> <span class="nv">$urun</span><span class="p">)</span><span class="o">:</span> <span class="cp">?&gt;</span>
    <span class="nt">&lt;article</span> <span class="na">class=</span><span class="s">"urun-karti"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;h2&gt;</span><span class="cp">&lt;?=</span> <span class="nb">htmlspecialchars</span><span class="p">(</span><span class="nv">$urun</span><span class="p">[</span><span class="s1">'ad'</span><span class="p">])</span> <span class="cp">?&gt;</span><span class="nt">&lt;/h2&gt;</span>
        <span class="nt">&lt;p&gt;</span><span class="cp">&lt;?=</span> <span class="nb">number_format</span><span class="p">(</span><span class="nv">$urun</span><span class="p">[</span><span class="s1">'fiyat'</span><span class="p">],</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">','</span><span class="p">,</span> <span class="s1">'.'</span><span class="p">)</span> <span class="cp">?&gt;</span> TL<span class="nt">&lt;/p&gt;</span>
        <span class="nt">&lt;strong&gt;</span>
            <span class="cp">&lt;?=</span> <span class="nv">$urun</span><span class="p">[</span><span class="s1">'stok'</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="s1">'Stokta var'</span> <span class="o">:</span> <span class="s1">'Tükendi'</span> <span class="cp">?&gt;</span>
        <span class="nt">&lt;/strong&gt;</span>
    <span class="nt">&lt;/article&gt;</span>
<span class="cp">&lt;?php</span> <span class="k">endforeach</span><span class="p">;</span> <span class="cp">?&gt;</span>
<span class="nt">&lt;/section&gt;</span>
</code></pre></div></div>

<p>Alternatif sözdizimindeki <code class="language-plaintext highlighter-rouge">foreach ... endforeach</code> yapısı, PHP ile HTML iç içeyken süslü parantezlere göre daha rahat okunur. <code class="language-plaintext highlighter-rouge">number_format()</code> fiyatı kullanıcı dostu hale getirirken üçlü koşul operatörü stok durumuna göre farklı metin üretir.</p>

<h2 id="boş-listeyi-unutmayın">Boş Listeyi Unutmayın</h2>

<p>Gerçek uygulamalarda veri kümesi her zaman dolu olmayabilir. Boş bir alan göstermek yerine kullanıcıya açıklama sunmak daha iyi bir deneyimdir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span> <span class="k">if</span> <span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$urunler</span><span class="p">))</span><span class="o">:</span> <span class="cp">?&gt;</span>
    <span class="nt">&lt;p&gt;</span>Henüz gösterilecek ürün bulunmuyor.<span class="nt">&lt;/p&gt;</span>
<span class="cp">&lt;?php</span> <span class="k">else</span><span class="o">:</span> <span class="cp">?&gt;</span>
    <span class="cp">&lt;?php</span> <span class="k">foreach</span> <span class="p">(</span><span class="nv">$urunler</span> <span class="k">as</span> <span class="nv">$urun</span><span class="p">)</span><span class="o">:</span> <span class="cp">?&gt;</span>
        <span class="nt">&lt;div&gt;</span><span class="cp">&lt;?=</span> <span class="nb">htmlspecialchars</span><span class="p">(</span><span class="nv">$urun</span><span class="p">[</span><span class="s1">'ad'</span><span class="p">])</span> <span class="cp">?&gt;</span><span class="nt">&lt;/div&gt;</span>
    <span class="cp">&lt;?php</span> <span class="k">endforeach</span><span class="p">;</span> <span class="cp">?&gt;</span>
<span class="cp">&lt;?php</span> <span class="k">endif</span><span class="p">;</span> <span class="cp">?&gt;</span>
</code></pre></div></div>

<p>Özetle sıra numarası, belirli aralık veya indeks denetimi gerekiyorsa <code class="language-plaintext highlighter-rouge">for</code>; verileri doğrudan ve okunaklı şekilde dolaşmak gerekiyorsa <code class="language-plaintext highlighter-rouge">foreach</code> tercih edilmelidir. Veriyi dizide tutup HTML şablonunu döngüyle çoğaltmak, tekrarları azaltır ve yeni bir kayıt eklemeyi yalnızca diziye tek satır eklemek kadar kolaylaştırır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="PHP" /><category term="Diziler" /><category term="Döngüler" /><summary type="html"><![CDATA[Bir web sayfasındaki ürün kartlarını tek tek elle yazmak, aynı şarkıyı yüz kez başa sarmaya benzer: yapılabilir ama hiç eğlenceli değildir. Diziler verileri düzenli biçimde saklarken for ve foreach döngüleri bu verileri sırayla işler. Böylece birkaç satırlık PHP koduyla onlarca HTML bloğunu dinamik, tutarlı ve kolay güncellenebilir biçimde ekrana basabiliriz.]]></summary></entry><entry><title type="html">Fonksiyonlar ve Modüler Kodlama: Kopyala-Yapıştır Döngüsünden Kurtulun</title><link href="https://sonsuzus.github.io/posts/fonksiyonlar-ve-moduler-kodlama-kopyala-yapistir-dongusunden-kurtulun/" rel="alternate" type="text/html" title="Fonksiyonlar ve Modüler Kodlama: Kopyala-Yapıştır Döngüsünden Kurtulun" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/fonksiyonlar-ve-moduler-kodlama-kopyala-yapistir-dongusunden-kurtulun</id><content type="html" xml:base="https://sonsuzus.github.io/posts/fonksiyonlar-ve-moduler-kodlama-kopyala-yapistir-dongusunden-kurtulun/"><![CDATA[<p>Bir program büyüdükçe aynı işlemleri farklı yerlerde tekrar tekrar yazmak, başlangıçta masum görünen bir alışkanlıktan ciddi bir bakım sorununa dönüşür. Fonksiyonlar ve modüler kodlama, bu tekrarları anlamlı parçalara ayırarak kodu daha okunabilir, test edilebilir ve yeniden kullanılabilir hâle getirir. Kısacası amaç, bilgisayara yalnızca ne yapacağını söylemek değil, bunu düzenli ve sürdürülebilir bir biçimde söylemektir.
``</p>
<h2 id="fonksiyon-nedir">Fonksiyon Nedir?</h2>

<p>Fonksiyon, belirli bir görevi gerçekleştiren ve gerektiğinde çağrılabilen isimlendirilmiş kod bloğudur. Bir fonksiyon girdiler alabilir, bu girdileri işleyebilir ve sonuç döndürebilir. Matematikteki fonksiyon fikriyle programlamadaki kullanım oldukça benzerdir:</p>

\[f(x) = x^2 + 2x + 1\]

<p>Burada $x$ girdi, $f(x)$ ise çıktıdır. Programlamada aynı yapı şöyle ifade edilebilir:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">hesapla</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">x² + 2x + 1 işleminin sonucunu döndürür.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">x</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>

<span class="n">sonuc</span> <span class="o">=</span> <span class="nf">hesapla</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">sonuc</span><span class="p">)</span>  <span class="c1"># 25
</span></code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">hesapla</code> fonksiyonu işlemin nasıl yapıldığını tek bir yerde saklar. Formül değişirse fonksiyonun kullanıldığı her satırı değil, yalnızca fonksiyon gövdesini güncellemek yeterlidir.</p>

<h2 id="tekrar-neden-tehlikelidir">Tekrar Neden Tehlikelidir?</h2>

<p>Aynı kodun birden fazla yerde bulunması, hata düzeltmelerini zorlaştırır. Örneğin indirim hesaplayan formülü beş farklı noktaya kopyaladıysanız oran değiştiğinde beş yeri de bulmanız gerekir. Birini unutursanız program farklı sonuçlar üretmeye başlar.</p>

<p>Tekrarlı kod miktarını kabaca şöyle düşünebiliriz:</p>

\[T = n \times m\]

<p>Burada $n$ tekrar sayısını, $m$ ise işlemin satır sayısını temsil eder. İşlem 8 satırsa ve 6 kez tekrarlanıyorsa toplam $48$ satır yönetilir. Fonksiyon kullanıldığında mantık yalnızca 8 satırda tutulur; diğer yerlerde kısa fonksiyon çağrıları bulunur.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th style="text-align: right">Okunabilirlik</th>
      <th style="text-align: right">Değişiklik Maliyeti</th>
      <th style="text-align: right">Yeniden Kullanım</th>
      <th style="text-align: right">Hata Riski</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kopyala-yapıştır</td>
      <td style="text-align: right">Düşük</td>
      <td style="text-align: right">Yüksek</td>
      <td style="text-align: right">Düşük</td>
      <td style="text-align: right">Yüksek</td>
    </tr>
    <tr>
      <td>Tek fonksiyon</td>
      <td style="text-align: right">Yüksek</td>
      <td style="text-align: right">Düşük</td>
      <td style="text-align: right">Yüksek</td>
      <td style="text-align: right">Düşük</td>
    </tr>
    <tr>
      <td>Modüllere ayrılmış yapı</td>
      <td style="text-align: right">Çok yüksek</td>
      <td style="text-align: right">Düşük</td>
      <td style="text-align: right">Çok yüksek</td>
      <td style="text-align: right">Düşük</td>
    </tr>
  </tbody>
</table>

<h2 id="parametreler-ve-dönüş-değerleri">Parametreler ve Dönüş Değerleri</h2>

<p>İyi tasarlanmış fonksiyonlar dışarıdan parametre alır ve sonucu <code class="language-plaintext highlighter-rouge">return</code> ile döndürür. Böylece belirli değerlere bağımlı kalmazlar.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">indirimli_fiyat</span><span class="p">(</span><span class="n">fiyat</span><span class="p">,</span> <span class="n">indirim_orani</span><span class="o">=</span><span class="mf">0.10</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Fiyata belirtilen oranda indirim uygular.</span><span class="sh">"""</span>
    <span class="k">if</span> <span class="n">fiyat</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">Fiyat negatif olamaz.</span><span class="sh">"</span><span class="p">)</span>

    <span class="n">indirim</span> <span class="o">=</span> <span class="n">fiyat</span> <span class="o">*</span> <span class="n">indirim_orani</span>
    <span class="k">return</span> <span class="n">fiyat</span> <span class="o">-</span> <span class="n">indirim</span>

<span class="n">urunler</span> <span class="o">=</span> <span class="p">[</span><span class="mi">250</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="mi">750</span><span class="p">]</span>
<span class="n">sonuclar</span> <span class="o">=</span> <span class="p">[</span><span class="nf">indirimli_fiyat</span><span class="p">(</span><span class="n">urun</span><span class="p">,</span> <span class="mf">0.20</span><span class="p">)</span> <span class="k">for</span> <span class="n">urun</span> <span class="ow">in</span> <span class="n">urunler</span><span class="p">]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">sonuclar</span><span class="p">)</span>
</code></pre></div></div>

<p>Fonksiyon hem farklı ürünlerde kullanılabilir hem de varsayılan indirim oranı sayesinde esnekliğini korur. Değer doğrulamasının fonksiyon içinde yapılması, hatalı verilerin sisteme sessizce yayılmasını da önler.</p>

<h2 id="modüler-kodlama-nedir">Modüler Kodlama Nedir?</h2>

<p>Fonksiyonlar tek tek görevleri düzenlerken modüler kodlama, ilişkili fonksiyonları ayrı dosyalarda toplar. Örneğin bir e-ticaret uygulamasında fiyat işlemleri <code class="language-plaintext highlighter-rouge">fiyat.py</code>, kullanıcı işlemleri <code class="language-plaintext highlighter-rouge">kullanici.py</code>, veritabanı işlemleri ise <code class="language-plaintext highlighter-rouge">veritabani.py</code> modülünde tutulabilir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># fiyat.py
</span><span class="k">def</span> <span class="nf">vergi_ekle</span><span class="p">(</span><span class="n">fiyat</span><span class="p">,</span> <span class="n">oran</span><span class="o">=</span><span class="mf">0.20</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">fiyat</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">oran</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">indirim_uygula</span><span class="p">(</span><span class="n">fiyat</span><span class="p">,</span> <span class="n">oran</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">fiyat</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">oran</span><span class="p">)</span>
</code></pre></div></div>

<p>Başka bir dosyada bu modül şöyle kullanılır:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">fiyat</span> <span class="kn">import</span> <span class="n">vergi_ekle</span><span class="p">,</span> <span class="n">indirim_uygula</span>

<span class="n">ara_toplam</span> <span class="o">=</span> <span class="nf">indirim_uygula</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="mf">0.15</span><span class="p">)</span>
<span class="n">toplam</span> <span class="o">=</span> <span class="nf">vergi_ekle</span><span class="p">(</span><span class="n">ara_toplam</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">toplam</span><span class="p">)</span>
</code></pre></div></div>

<p>Bu ayrım, ana programın ayrıntılara boğulmasını engeller. Kod, uzun bir yapılacaklar listesi yerine anlamlı görevlerin orkestrasyonu gibi görünür.</p>

<h2 id="i̇yi-fonksiyon-yazmanın-altın-kuralları">İyi Fonksiyon Yazmanın Altın Kuralları</h2>

<ul>
  <li>Her fonksiyon mümkünse <strong>tek bir sorumluluğa</strong> sahip olmalıdır.</li>
  <li><code class="language-plaintext highlighter-rouge">islem1</code> yerine <code class="language-plaintext highlighter-rouge">siparis_toplamini_hesapla</code> gibi açıklayıcı isimler kullanılmalıdır.</li>
  <li>Gereksiz küresel değişkenlerden kaçınılmalıdır.</li>
  <li>Çok fazla parametre alan fonksiyonlar yeniden tasarlanmalıdır.</li>
  <li>Tekrarlanan mantık ortak bir fonksiyona taşınmalıdır.</li>
  <li>Fonksiyonlar küçük ve bağımsız testlerle doğrulanmalıdır.</li>
</ul>

<p>Fonksiyonlara ayırmak yalnızca satır sayısını azaltmaz; programın düşünce yapısını görünür kılar. Kodunuzda sık sık kopyala-yapıştır yapıyorsanız küçük bir alarm çalmalıdır: Orada muhtemelen keşfedilmeyi bekleyen bir fonksiyon vardır!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="fonksiyonlar" /><category term="modüler programlama" /><category term="temiz kod" /><summary type="html"><![CDATA[Bir program büyüdükçe aynı işlemleri farklı yerlerde tekrar tekrar yazmak, başlangıçta masum görünen bir alışkanlıktan ciddi bir bakım sorununa dönüşür. Fonksiyonlar ve modüler kodlama, bu tekrarları anlamlı parçalara ayırarak kodu daha okunabilir, test edilebilir ve yeniden kullanılabilir hâle getirir. Kısacası amaç, bilgisayara yalnızca ne yapacağını söylemek değil, bunu düzenli ve sürdürülebilir bir biçimde söylemektir.]]></summary></entry><entry><title type="html">Form İşlemleri ve Güvenli Veri Doğrulama Rehberi</title><link href="https://sonsuzus.github.io/posts/form-islemleri-ve-guvenli-veri-dogrulama-rehberi/" rel="alternate" type="text/html" title="Form İşlemleri ve Güvenli Veri Doğrulama Rehberi" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/form-islemleri-ve-guvenli-veri-dogrulama-rehberi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/form-islemleri-ve-guvenli-veri-dogrulama-rehberi/"><![CDATA[<p>Bir web formu, kullanıcı ile sunucu arasındaki dijital köprüdür. Ancak bu köprüden yalnızca isimler ve e-posta adresleri geçmez; hatalı değerler, bot istekleri ve kötü niyetli SQL parçaları da geçmeye çalışabilir. Bu nedenle veriyi doğrudan veritabanına göndermek, kapının anahtarını paspasın altına bırakmaya benzer.
``</p>

<h2 id="formdan-veritabanına-uzanan-yol">Formdan veritabanına uzanan yol</h2>

<p>Tarayıcıda doldurulan alanlar genellikle <code class="language-plaintext highlighter-rouge">GET</code> veya <code class="language-plaintext highlighter-rouge">POST</code> yöntemiyle sunucuya iletilir. <code class="language-plaintext highlighter-rouge">GET</code>, filtreleme ve arama gibi adres çubuğunda görülebilecek işlemler için uygundur. Kişisel bilgiler veya veri değiştiren işlemler ise çoğunlukla <code class="language-plaintext highlighter-rouge">POST</code> kullanmalıdır. Yine de <code class="language-plaintext highlighter-rouge">POST</code> veriyi kendiliğinden güvenli yapmaz; yalnızca URL dışında taşır. İletişimin şifrelenmesi için HTTPS gerekir.</p>

<p>Sağlıklı bir veri akışı şu aşamalardan oluşur:</p>

<ol>
  <li>İstek yöntemini ve içerik türünü kontrol etme</li>
  <li>Beklenen alanları alma</li>
  <li>Veriyi normalize etme ve gereksiz boşlukları temizleme</li>
  <li>Tür, biçim, uzunluk ve iş kuralı doğrulaması yapma</li>
  <li>Parametreli sorguyla veritabanına yazma</li>
  <li>Gösterim sırasında bağlama uygun çıktı kodlaması uygulama</li>
</ol>

<h2 id="filtreleme-ve-doğrulama-aynı-şey-değildir">Filtreleme ve doğrulama aynı şey değildir</h2>

<table>
  <thead>
    <tr>
      <th>İşlem</th>
      <th>Amacı</th>
      <th>Örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Normalizasyon</td>
      <td>Veriyi standart biçime getirmek</td>
      <td>Baştaki boşlukları silmek</td>
    </tr>
    <tr>
      <td>Filtreleme</td>
      <td>İstenmeyen karakterleri ayıklamak</td>
      <td>Kontrol karakterlerini kaldırmak</td>
    </tr>
    <tr>
      <td>Doğrulama</td>
      <td>Değerin kurala uyduğunu sınamak</td>
      <td>E-posta biçimini kontrol etmek</td>
    </tr>
    <tr>
      <td>Kodlama</td>
      <td>Veriyi hedef bağlamda güvenli göstermek</td>
      <td>HTML karakterlerini dönüştürmek</td>
    </tr>
  </tbody>
</table>

<p>Bir alanın kabul koşulunu matematiksel olarak şöyle düşünebiliriz:</p>

\[V(x)=T(x) \land L_{min}\leq |x|\leq L_{max} \land B(x)\]

<table>
  <tbody>
    <tr>
      <td>Burada $T(x)$ biçim ve tür kontrolünü, $</td>
      <td>x</td>
      <td>$ uzunluğu, $B(x)$ ise uygulamanın iş kurallarını temsil eder. Koşullardan biri bile yanlışsa veri reddedilmelidir. Hatalı girdiyi sessizce değiştirmek yerine kullanıcıya anlaşılır bir mesaj göstermek çoğu zaman daha doğrudur.</td>
    </tr>
  </tbody>
</table>

<h2 id="sunucu-tarafında-güvenli-örnek">Sunucu tarafında güvenli örnek</h2>

<p>Aşağıdaki PHP örneği; adı, e-posta adresini ve yaşı doğrular. Tarayıcıdaki <code class="language-plaintext highlighter-rouge">required</code>, <code class="language-plaintext highlighter-rouge">min</code> veya <code class="language-plaintext highlighter-rouge">type="email"</code> kontrolleri kullanıcı deneyimini iyileştirir, fakat geliştirici araçlarıyla aşılabildiği için güvenlik sınırı sayılmaz.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$_SERVER</span><span class="p">[</span><span class="s1">'REQUEST_METHOD'</span><span class="p">]</span> <span class="o">!==</span> <span class="s1">'POST'</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">http_response_code</span><span class="p">(</span><span class="mi">405</span><span class="p">);</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Yalnızca POST kabul edilir.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nv">$name</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nv">$_POST</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$email</span> <span class="o">=</span> <span class="nb">filter_input</span><span class="p">(</span><span class="no">INPUT_POST</span><span class="p">,</span> <span class="s1">'email'</span><span class="p">,</span> <span class="no">FILTER_VALIDATE_EMAIL</span><span class="p">);</span>
<span class="nv">$age</span> <span class="o">=</span> <span class="nb">filter_input</span><span class="p">(</span><span class="no">INPUT_POST</span><span class="p">,</span> <span class="s1">'age'</span><span class="p">,</span> <span class="no">FILTER_VALIDATE_INT</span><span class="p">,</span> <span class="p">[</span>
    <span class="s1">'options'</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="s1">'min_range'</span> <span class="o">=&gt;</span> <span class="mi">18</span><span class="p">,</span> <span class="s1">'max_range'</span> <span class="o">=&gt;</span> <span class="mi">120</span><span class="p">]</span>
<span class="p">]);</span>

<span class="nv">$errors</span> <span class="o">=</span> <span class="p">[];</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$name</span> <span class="o">===</span> <span class="s1">''</span> <span class="o">||</span> <span class="nb">mb_strlen</span><span class="p">(</span><span class="nv">$name</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">80</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$errors</span><span class="p">[]</span> <span class="o">=</span> <span class="s1">'Ad alanı 1-80 karakter olmalıdır.'</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$email</span> <span class="o">===</span> <span class="kc">false</span> <span class="o">||</span> <span class="nv">$email</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$errors</span><span class="p">[]</span> <span class="o">=</span> <span class="s1">'Geçerli bir e-posta adresi girilmelidir.'</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$age</span> <span class="o">===</span> <span class="kc">false</span> <span class="o">||</span> <span class="nv">$age</span> <span class="o">===</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
    <span class="nv">$errors</span><span class="p">[]</span> <span class="o">=</span> <span class="s1">'Yaş 18 ile 120 arasında olmalıdır.'</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$errors</span><span class="p">)</span> <span class="p">{</span>
    <span class="nb">http_response_code</span><span class="p">(</span><span class="mi">422</span><span class="p">);</span>
    <span class="k">exit</span><span class="p">(</span><span class="nb">implode</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="nv">$errors</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Kod, eksik alanlar için varsayılan değer kullanır ve her hatayı ayrı biçimde toplar. HTTP <code class="language-plaintext highlighter-rouge">422</code> cevabı, isteğin anlaşılmasına rağmen verilerin kurallara uymadığını belirtir.</p>

<h2 id="sql-enjeksiyonuna-kapıyı-kapatmak">SQL enjeksiyonuna kapıyı kapatmak</h2>

<p>Doğrulanan değerler bile SQL metnine birleştirilmemelidir. PDO prepared statement kullanıldığında sorgu ile veri ayrı kanallardan işlenir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$stmt</span> <span class="o">=</span> <span class="nv">$pdo</span><span class="o">-&gt;</span><span class="nf">prepare</span><span class="p">(</span>
    <span class="s1">'INSERT INTO users (name, email, age) VALUES (:name, :email, :age)'</span>
<span class="p">);</span>

<span class="nv">$stmt</span><span class="o">-&gt;</span><span class="nf">execute</span><span class="p">([</span>
    <span class="s1">'name'</span> <span class="o">=&gt;</span> <span class="nv">$name</span><span class="p">,</span>
    <span class="s1">'email'</span> <span class="o">=&gt;</span> <span class="nv">$email</span><span class="p">,</span>
    <span class="s1">'age'</span> <span class="o">=&gt;</span> <span class="nv">$age</span>
<span class="p">]);</span>
</code></pre></div></div>

<p>Bu yaklaşım SQL enjeksiyonuna karşı temel savunmadır. Veritabanında ayrıca <code class="language-plaintext highlighter-rouge">UNIQUE</code>, <code class="language-plaintext highlighter-rouge">NOT NULL</code> ve uygun sütun türleri tanımlanmalıdır; çünkü güvenlik tek bir kontrol noktasına emanet edilmez.</p>

<p>Son olarak formlara CSRF token eklenmeli, hassas alanlar günlüklere yazılmamalı ve hata mesajlarında sorgu ayrıntıları gösterilmemelidir. Veritabanından okunan içerik HTML içinde sunulurken <code class="language-plaintext highlighter-rouge">htmlspecialchars</code> ile kodlanmalıdır. Kısacası doğru sıra şudur: istemcide kolaylaştır, sunucuda doğrula, parametreli sorguyla kaydet ve gösterirken güvenli biçimde kodla.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="form işlemleri" /><category term="veri doğrulama" /><category term="web güvenliği" /><summary type="html"><![CDATA[Bir web formu, kullanıcı ile sunucu arasındaki dijital köprüdür. Ancak bu köprüden yalnızca isimler ve e-posta adresleri geçmez; hatalı değerler, bot istekleri ve kötü niyetli SQL parçaları da geçmeye çalışabilir. Bu nedenle veriyi doğrudan veritabanına göndermek, kapının anahtarını paspasın altına bırakmaya benzer.]]></summary></entry><entry><title type="html">Geometrik Algoritmalar: Dışbükey Örtüden Tarama Doğrusuna</title><link href="https://sonsuzus.github.io/posts/geometrik-algoritmalar-disbukey-ortuden-tarama-dogrusuna/" rel="alternate" type="text/html" title="Geometrik Algoritmalar: Dışbükey Örtüden Tarama Doğrusuna" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/geometrik-algoritmalar-disbukey-ortuden-tarama-dogrusuna</id><content type="html" xml:base="https://sonsuzus.github.io/posts/geometrik-algoritmalar-disbukey-ortuden-tarama-dogrusuna/"><![CDATA[<p>Haritadaki noktaları çevreleyen en kısa çiti bulmak, kesişen yol parçalarını tespit etmek veya bir çokgenin alanını hesaplamak… Bilgisayarlı geometrinin bu klasik problemleri, birkaç temel işlem üzerine kurulur. Nokta, doğru ve çokgenleri matematiksel olarak temsil etmeyi öğrendiğimizde dışbükey örtü ve tarama doğrusu gibi ilk bakışta ürkütücü görünen algoritmalar oldukça anlaşılır hâle gelir.
``</p>

<h2 id="geometrinin-yapı-taşları">Geometrinin yapı taşları</h2>

<p>İki boyutlu düzlemde bir noktayı $P=(x,y)$ biçiminde gösteririz. İki noktanın farkı ise bir vektördür: $AB=B-A$. Uzaklık hesabında Öklid formülü kullanılır:</p>

\[d(A,B)=\sqrt{(x_B-x_A)^2+(y_B-y_A)^2}\]

<p>Geometrik algoritmaların gizli kahramanı çapraz çarpımdır. $A$, $B$ ve $C$ noktaları için yönelim değeri şöyledir:</p>

\[cross(A,B,C)=(B_x-A_x)(C_y-A_y)-(B_y-A_y)(C_x-A_x)\]

<p>Sonucun işareti, üç noktanın dönüş yönünü söyler:</p>

<table>
  <thead>
    <tr>
      <th>Sonuç</th>
      <th>Geometrik anlam</th>
      <th>Algoritmadaki kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$cross&gt;0$</td>
      <td>Sola dönüş</td>
      <td>Saat yönünün tersinde ilerleme</td>
    </tr>
    <tr>
      <td>$cross&lt;0$</td>
      <td>Sağa dönüş</td>
      <td>Uygun olmayan noktayı çıkarma</td>
    </tr>
    <tr>
      <td>$cross=0$</td>
      <td>Noktalar doğrusal</td>
      <td>Çakışma ve sınır kontrolü</td>
    </tr>
  </tbody>
</table>

<p>Bu işlem yalnızca çarpma ve çıkarma içerdiği için açı hesaplamaktan daha hızlıdır. Tamsayı koordinatlarda kayan nokta hatalarını da önler.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Point</span> <span class="p">{</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="nf">cross</span><span class="p">(</span><span class="n">Point</span> <span class="n">a</span><span class="p">,</span> <span class="n">Point</span> <span class="n">b</span><span class="p">,</span> <span class="n">Point</span> <span class="n">c</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="n">x</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="n">y</span><span class="p">)</span>
         <span class="o">-</span> <span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="n">y</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">a</span><span class="p">.</span><span class="n">x</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Bu fonksiyon; dönüş yönü, doğru parçalarının kesişimi ve dışbükeylik kontrolü gibi birçok işlemin ortak motorudur.</p>

<h2 id="çokgen-alanı-ve-yönü">Çokgen alanı ve yönü</h2>

<p>Köşeleri sırayla verilen basit bir çokgenin alanı, ayakkabı bağı formülüyle bulunabilir:</p>

\[2A=\left|\sum_{i=0}^{n-1}(x_i y_{i+1}-y_i x_{i+1})\right|\]

<p>İndisler döngüseldir; yani son noktadan sonra yeniden ilk nokta gelir. Mutlak değer alınmadan önce toplamın işareti, köşelerin saat yönünde mi yoksa ters yönde mi sıralandığını da gösterir.</p>

<h2 id="dışbükey-örtü-noktaların-etrafına-lastik-geçirmek">Dışbükey örtü: Noktaların etrafına lastik geçirmek</h2>

<p>Dışbükey örtü, verilen bütün noktaları kapsayan en küçük dışbükey çokgendir. Sezgisel olarak noktaların çevresine bir lastik geçirip bıraktığımızda oluşan sınırdır. Monotonic Chain algoritması önce noktaları $(x,y)$ sırasına göre sıralar, ardından alt ve üst zincirleri kurar.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vector</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span> <span class="n">convexHull</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span> <span class="n">p</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">p</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[](</span><span class="n">Point</span> <span class="n">a</span><span class="p">,</span> <span class="n">Point</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">x</span> <span class="o">!=</span> <span class="n">b</span><span class="p">.</span><span class="n">x</span> <span class="o">?</span> <span class="n">a</span><span class="p">.</span><span class="n">x</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">x</span> <span class="o">:</span> <span class="n">a</span><span class="p">.</span><span class="n">y</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">y</span><span class="p">;</span>
    <span class="p">});</span>

    <span class="n">vector</span><span class="o">&lt;</span><span class="n">Point</span><span class="o">&gt;</span> <span class="n">h</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">pass</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">pass</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="n">pass</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">size_t</span> <span class="n">start</span> <span class="o">=</span> <span class="n">h</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">Point</span> <span class="n">q</span> <span class="o">:</span> <span class="n">p</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">while</span> <span class="p">(</span><span class="n">h</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="n">start</span> <span class="o">+</span> <span class="mi">2</span> <span class="o">&amp;&amp;</span>
                   <span class="n">cross</span><span class="p">(</span><span class="n">h</span><span class="p">[</span><span class="n">h</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">h</span><span class="p">.</span><span class="n">back</span><span class="p">(),</span> <span class="n">q</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span>
                <span class="n">h</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span>
            <span class="n">h</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">q</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">h</span><span class="p">.</span><span class="n">pop_back</span><span class="p">();</span>
        <span class="n">reverse</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">p</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">h</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Sıralama $O(n\log n)$, zincirleri oluşturma ise $O(n)$ sürer. <code class="language-plaintext highlighter-rouge">cross &lt;= 0</code> kullanımı, aynı kenar üzerindeki ara noktaları örtüden çıkarır. Bu noktalar da sonuçta isteniyorsa koşul problem tanımına göre değiştirilmelidir.</p>

<h2 id="tarama-doğrusu-olayları-sırayla-işle">Tarama doğrusu: Olayları sırayla işle</h2>

<p>Tarama doğrusu yaklaşımında hayali bir doğru düzlem boyunca hareket eder. Algoritma bütün geometrik şekilleri sürekli incelemek yerine yalnızca başlangıç, bitiş ve kesişim gibi <strong>olaylarda</strong> işlem yapar.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Temel fikir</th>
      <th>Tipik karmaşıklık</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tüm çiftleri deneme</td>
      <td>Her doğru parçasını diğerleriyle karşılaştır</td>
      <td>$O(n^2)$</td>
    </tr>
    <tr>
      <td>Tarama doğrusu</td>
      <td>Olayları sırala, aktif elemanları tut</td>
      <td>Genellikle $O(n\log n)$</td>
    </tr>
    <tr>
      <td>Dışbükey örtü</td>
      <td>Gereksiz iç noktaları ele</td>
      <td>$O(n\log n)$</td>
    </tr>
  </tbody>
</table>

<p>Örneğin yatay doğru parçalarının çakışmasını ararken başlangıç noktası aktif kümeye eklenir, bitiş noktası geldiğinde çıkarılır. Dikey bir parça işlendiğinde aktif kümede onun $y$ aralığına düşen parçalar sorgulanır. Dengeli bir arama ağacı kullanılırsa ekleme, silme ve arama işlemleri $O(\log n)$ zamanda yapılabilir.</p>

<p>Tarama doğrusu uygulamalarındaki kritik ayrıntı, aynı koordinattaki olayların sırasıdır. Bir parçanın bitişi, diğerinin başlangıcıyla çakışıyorsa kesişimin sayılıp sayılmayacağına göre olay öncelikleri belirlenmelidir. Geometride şeytan ayrıntıda, hata ise çoğunlukla eşitlik durumundadır!</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="geometri" /><category term="algoritma" /><category term="dışbükey örtü" /><summary type="html"><![CDATA[Haritadaki noktaları çevreleyen en kısa çiti bulmak, kesişen yol parçalarını tespit etmek veya bir çokgenin alanını hesaplamak… Bilgisayarlı geometrinin bu klasik problemleri, birkaç temel işlem üzerine kurulur. Nokta, doğru ve çokgenleri matematiksel olarak temsil etmeyi öğrendiğimizde dışbükey örtü ve tarama doğrusu gibi ilk bakışta ürkütücü görünen algoritmalar oldukça anlaşılır hâle gelir.]]></summary></entry><entry><title type="html">Güvenli Dosya Yükleme: Formdan Sunucuya Sağlam Bir Yolculuk</title><link href="https://sonsuzus.github.io/posts/guvenli-dosya-yukleme-formdan-sunucuya-saglam-bir-yolculuk/" rel="alternate" type="text/html" title="Güvenli Dosya Yükleme: Formdan Sunucuya Sağlam Bir Yolculuk" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/guvenli-dosya-yukleme-formdan-sunucuya-saglam-bir-yolculuk</id><content type="html" xml:base="https://sonsuzus.github.io/posts/guvenli-dosya-yukleme-formdan-sunucuya-saglam-bir-yolculuk/"><![CDATA[<p>Dosya yükleme özelliği, profil fotoğrafından PDF başvuru belgelerine kadar pek çok web uygulamasının vazgeçilmezidir. Ancak kullanıcıdan gelen bir dosyayı doğrudan sunucuya kabul etmek, kapıyı çalan herkese anahtarı teslim etmeye benzeyebilir. Güvenli bir sistem; dosyanın adını, boyutunu, gerçek türünü ve saklanacağı konumu denetlemelidir.</p>

<p>``</p>

<h2 id="dosya-yükleme-nasıl-çalışır">Dosya yükleme nasıl çalışır?</h2>

<p>Tarayıcı, dosyayı genellikle <code class="language-plaintext highlighter-rouge">multipart/form-data</code> biçiminde HTTP isteğine ekler. Sunucu dosyayı geçici bir dizine alır, uygulama da doğrulama tamamlandıktan sonra kalıcı konuma taşır. Kritik nokta şudur: <strong>Kullanıcı tarafından gönderilen hiçbir bilgi güvenilir kabul edilmemelidir.</strong></p>

<p>Bir yükleme isteğinin yaklaşık maliyetini şöyle düşünebiliriz:</p>

\[M_{toplam} = M_{dosya} + M_{istek} + M_{işleme}\]

<p>Burada büyük dosyalar yalnızca disk alanını değil; ağ trafiğini, belleği ve işlem süresini de tüketir. Bu nedenle uygulama seviyesindeki sınırın yanında web sunucusu ve PHP yapılandırmasında da boyut sınırı bulunmalıdır.</p>

<table>
  <thead>
    <tr>
      <th>Kontrol</th>
      <th>Güvensiz yaklaşım</th>
      <th>Güvenli yaklaşım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dosya türü</td>
      <td>Uzantıya bakmak</td>
      <td>İçeriğin MIME türünü incelemek</td>
    </tr>
    <tr>
      <td>Dosya adı</td>
      <td>Kullanıcının adını korumak</td>
      <td>Rastgele ve benzersiz ad üretmek</td>
    </tr>
    <tr>
      <td>Boyut</td>
      <td>Sınırsız kabul etmek</td>
      <td>Uygun üst sınır belirlemek</td>
    </tr>
    <tr>
      <td>Saklama</td>
      <td>Herkese açık dizine koymak</td>
      <td>Web kökü dışında saklamak</td>
    </tr>
    <tr>
      <td>Hata mesajı</td>
      <td>Sistem yolunu göstermek</td>
      <td>Genel ve kontrollü mesaj vermek</td>
    </tr>
  </tbody>
</table>

<h2 id="formun-hazırlanması">Formun hazırlanması</h2>

<p>Formda <code class="language-plaintext highlighter-rouge">enctype</code> belirtilmezse dosya içeriği sunucuya doğru biçimde ulaşmaz:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;form</span> <span class="na">action=</span><span class="s">"upload.php"</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">enctype=</span><span class="s">"multipart/form-data"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"csrf_token"</span> <span class="na">value=</span><span class="s">"SUNUCUDA_URETILEN_TOKEN"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"file"</span> <span class="na">name=</span><span class="s">"document"</span> <span class="na">accept=</span><span class="s">"image/jpeg,image/png,application/pdf"</span> <span class="na">required</span><span class="nt">&gt;</span>
  <span class="nt">&lt;button</span> <span class="na">type=</span><span class="s">"submit"</span><span class="nt">&gt;</span>Güvenli biçimde yükle<span class="nt">&lt;/button&gt;</span>
<span class="nt">&lt;/form&gt;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">accept</code> özelliği kullanıcı deneyimini iyileştirir fakat güvenlik önlemi değildir; istek elle değiştirilerek başka dosyalar gönderilebilir. CSRF belirteci ise başka bir sitenin kullanıcı adına yükleme başlatmasını zorlaştırır.</p>

<h2 id="php-ile-güvenli-doğrulama">PHP ile güvenli doğrulama</h2>

<p>Aşağıdaki örnek; yükleme hatasını, boyutu ve gerçek MIME türünü denetler. Ayrıca tahmin edilmesi güç bir dosya adı üretir:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>
<span class="nb">session_start</span><span class="p">();</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">hash_equals</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">'csrf_token'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$_POST</span><span class="p">[</span><span class="s1">'csrf_token'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">))</span> <span class="p">{</span>
    <span class="nb">http_response_code</span><span class="p">(</span><span class="mi">403</span><span class="p">);</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Geçersiz istek.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nv">$file</span> <span class="o">=</span> <span class="nv">$_FILES</span><span class="p">[</span><span class="s1">'document'</span><span class="p">]</span> <span class="o">??</span> <span class="kc">null</span><span class="p">;</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$file</span> <span class="o">||</span> <span class="nv">$file</span><span class="p">[</span><span class="s1">'error'</span><span class="p">]</span> <span class="o">!==</span> <span class="no">UPLOAD_ERR_OK</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Dosya yüklenemedi.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nv">$maxSize</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">;</span> <span class="c1">// 5 MB</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$file</span><span class="p">[</span><span class="s1">'size'</span><span class="p">]</span> <span class="o">&gt;</span> <span class="nv">$maxSize</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Dosya boyutu sınırı aşıldı.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nv">$finfo</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">finfo</span><span class="p">(</span><span class="no">FILEINFO_MIME_TYPE</span><span class="p">);</span>
<span class="nv">$mime</span> <span class="o">=</span> <span class="nv">$finfo</span><span class="o">-&gt;</span><span class="nb">file</span><span class="p">(</span><span class="nv">$file</span><span class="p">[</span><span class="s1">'tmp_name'</span><span class="p">]);</span>
<span class="nv">$allowed</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s1">'image/jpeg'</span> <span class="o">=&gt;</span> <span class="s1">'jpg'</span><span class="p">,</span>
    <span class="s1">'image/png'</span> <span class="o">=&gt;</span> <span class="s1">'png'</span><span class="p">,</span>
    <span class="s1">'application/pdf'</span> <span class="o">=&gt;</span> <span class="s1">'pdf'</span>
<span class="p">];</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">isset</span><span class="p">(</span><span class="nv">$allowed</span><span class="p">[</span><span class="nv">$mime</span><span class="p">]))</span> <span class="p">{</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Desteklenmeyen dosya türü.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="nv">$name</span> <span class="o">=</span> <span class="nb">bin2hex</span><span class="p">(</span><span class="nb">random_bytes</span><span class="p">(</span><span class="mi">16</span><span class="p">))</span> <span class="mf">.</span> <span class="s1">'.'</span> <span class="mf">.</span> <span class="nv">$allowed</span><span class="p">[</span><span class="nv">$mime</span><span class="p">];</span>
<span class="nv">$target</span> <span class="o">=</span> <span class="nb">dirname</span><span class="p">(</span><span class="k">__DIR__</span><span class="p">)</span> <span class="mf">.</span> <span class="s1">'/private_uploads/'</span> <span class="mf">.</span> <span class="nv">$name</span><span class="p">;</span>

<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">move_uploaded_file</span><span class="p">(</span><span class="nv">$file</span><span class="p">[</span><span class="s1">'tmp_name'</span><span class="p">],</span> <span class="nv">$target</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">exit</span><span class="p">(</span><span class="s1">'Dosya kaydedilemedi.'</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">echo</span> <span class="s1">'Yükleme tamamlandı.'</span><span class="p">;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">finfo</code>, yalnızca kullanıcının bildirdiği türe güvenmek yerine dosya içeriğini inceler. <code class="language-plaintext highlighter-rouge">random_bytes</code> tabanlı adlandırma ise <code class="language-plaintext highlighter-rouge">rapor.php.jpg</code> gibi yanıltıcı adları ve aynı isimli dosyaların birbirini ezmesini engeller.</p>

<h2 id="görseller-için-ek-savunmalar">Görseller için ek savunmalar</h2>

<p>Bir dosyanın MIME türünün görsel görünmesi, tamamen güvenli olduğu anlamına gelmez. Görseller mümkünse GD veya Imagick ile açılıp yeniden kodlanmalıdır. Belgeler antivirüs servisiyle taranabilir; yüksek riskli sistemlerde tarama bitene kadar karantina dizininde tutulmalıdır.</p>

<table>
  <thead>
    <tr>
      <th>Katman</th>
      <th>Önerilen önlem</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Uygulama</td>
      <td>MIME, boyut, yetki ve CSRF kontrolü</td>
    </tr>
    <tr>
      <td>Dosya sistemi</td>
      <td>Yazma iznini sınırlama, çalıştırmayı kapatma</td>
    </tr>
    <tr>
      <td>Sunucu</td>
      <td>İstek ve zaman aşımı sınırları</td>
    </tr>
    <tr>
      <td>Operasyon</td>
      <td>Zararlı yazılım taraması ve kayıt tutma</td>
    </tr>
  </tbody>
</table>

<p>Son olarak dosyaları doğrudan tahmin edilebilir URL’lerle sunmak yerine, kullanıcının erişim yetkisini kontrol eden bir indirme uç noktası kullanın. Böylece güvenli yükleme tek bir <code class="language-plaintext highlighter-rouge">if</code> koşulu değil, birbirini tamamlayan savunma katmanlarından oluşan sağlam bir kale hâline gelir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="dosya-yükleme" /><category term="web-güvenliği" /><category term="php" /><summary type="html"><![CDATA[Dosya yükleme özelliği, profil fotoğrafından PDF başvuru belgelerine kadar pek çok web uygulamasının vazgeçilmezidir. Ancak kullanıcıdan gelen bir dosyayı doğrudan sunucuya kabul etmek, kapıyı çalan herkese anahtarı teslim etmeye benzeyebilir. Güvenli bir sistem; dosyanın adını, boyutunu, gerçek türünü ve saklanacağı konumu denetlemelidir.]]></summary></entry><entry><title type="html">İlişkisel Veri Sorguları: INNER JOIN ve LEFT JOIN Rehberi</title><link href="https://sonsuzus.github.io/posts/iliskisel-veri-sorgulari-inner-join-ve-left-join-rehberi/" rel="alternate" type="text/html" title="İlişkisel Veri Sorguları: INNER JOIN ve LEFT JOIN Rehberi" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/iliskisel-veri-sorgulari-inner-join-ve-left-join-rehberi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/iliskisel-veri-sorgulari-inner-join-ve-left-join-rehberi/"><![CDATA[<p>Bir e-ticaret sisteminde müşteriler bir tabloda, siparişler başka bir tabloda tutulur. Peki “Hangi müşteri hangi siparişi verdi?” sorusunu nasıl yanıtlarız? SQL dünyasının çöpçatanı <code class="language-plaintext highlighter-rouge">JOIN</code>, farklı tablolardaki ilişkili satırları ortak sütunlar üzerinden buluşturur ve sonuçları tek bir sanal tablo gibi sunar.
``</p>
<h2 id="i̇lişkisel-modelin-temel-mantığı">İlişkisel modelin temel mantığı</h2>

<p>İlişkisel veritabanlarında bilgiler, gereksiz tekrarı azaltmak amacıyla farklı tablolara ayrılır. Örneğin her sipariş satırına müşterinin adını ve e-posta adresini yazmak yerine, sipariş tablosunda yalnızca müşteriyi işaret eden bir kimlik tutulur.</p>

<p><code class="language-plaintext highlighter-rouge">musteriler</code> tablosundaki <code class="language-plaintext highlighter-rouge">id</code> alanı <strong>birincil anahtar</strong> (<code class="language-plaintext highlighter-rouge">PRIMARY KEY</code>), <code class="language-plaintext highlighter-rouge">siparisler</code> tablosundaki <code class="language-plaintext highlighter-rouge">musteri_id</code> alanı ise <strong>yabancı anahtar</strong> (<code class="language-plaintext highlighter-rouge">FOREIGN KEY</code>) olabilir. Aralarındaki ilişki şöyle ifade edilir:</p>

\[Musteriler.id = Siparisler.musteri\_id\]

<p>Bir müşteri birden fazla sipariş verebildiği için bu, bire-çok ilişkisidir. Müşteri başına ortalama sipariş sayısı basitçe şu şekilde düşünülebilir:</p>

\[Ortalama = \frac{Toplam\ Siparis\ Sayisi}{Toplam\ Musteri\ Sayisi}\]

<p>JOIN işlemi tabloları fiziksel olarak birleştirmez. Sorgu çalışırken koşula uyan satırlardan geçici bir sonuç kümesi üretir. Yani veritabanı mobilyalarını birbirine vidalamaz; yalnızca aynı fotoğraf karesine alır.</p>

<h2 id="inner-join-ve-left-join-karşılaştırması">INNER JOIN ve LEFT JOIN karşılaştırması</h2>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>INNER JOIN</th>
      <th>LEFT JOIN</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Eşleşen kayıtlar</td>
      <td>Getirilir</td>
      <td>Getirilir</td>
    </tr>
    <tr>
      <td>Sol tabloda eşleşmeyen kayıtlar</td>
      <td>Getirilmez</td>
      <td>Getirilir</td>
    </tr>
    <tr>
      <td>Eksik sağ taraf değerleri</td>
      <td>Sonuçta bulunmaz</td>
      <td><code class="language-plaintext highlighter-rouge">NULL</code> olur</td>
    </tr>
    <tr>
      <td>Tipik kullanım</td>
      <td>Yalnızca ilişkili veriler</td>
      <td>Ana listedeki tüm kayıtlar</td>
    </tr>
  </tbody>
</table>

<h3 id="inner-join-kullanımı">INNER JOIN kullanımı</h3>

<p><code class="language-plaintext highlighter-rouge">INNER JOIN</code>, iki tabloda da eşleşmesi bulunan satırları döndürür. Sipariş vermiş müşterileri ve siparişlerini listeleyelim:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span>
    <span class="n">m</span><span class="p">.</span><span class="n">id</span><span class="p">,</span>
    <span class="n">m</span><span class="p">.</span><span class="n">ad</span><span class="p">,</span>
    <span class="n">s</span><span class="p">.</span><span class="n">id</span> <span class="k">AS</span> <span class="n">siparis_id</span><span class="p">,</span>
    <span class="n">s</span><span class="p">.</span><span class="n">tutar</span>
<span class="k">FROM</span> <span class="n">musteriler</span> <span class="k">AS</span> <span class="n">m</span>
<span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">siparisler</span> <span class="k">AS</span> <span class="n">s</span>
    <span class="k">ON</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">musteri_id</span><span class="p">;</span>
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">ON</code> bölümü eşleşmenin hangi koşula göre yapılacağını belirtir. <code class="language-plaintext highlighter-rouge">AS</code> ile tanımlanan kısa tablo adları sorguyu okunabilir kılar. Siparişi olmayan bir müşteri bu sonuçta görünmez; çünkü eşleşme yalnızca tek tarafta kalmıştır.</p>

<h3 id="left-join-kullanımı">LEFT JOIN kullanımı</h3>

<p>Şimdi mağazaya kayıtlı bütün müşterileri, sipariş vermemiş olsalar bile görmek istediğimizi düşünelim:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span>
    <span class="n">m</span><span class="p">.</span><span class="n">id</span><span class="p">,</span>
    <span class="n">m</span><span class="p">.</span><span class="n">ad</span><span class="p">,</span>
    <span class="n">s</span><span class="p">.</span><span class="n">id</span> <span class="k">AS</span> <span class="n">siparis_id</span><span class="p">,</span>
    <span class="n">s</span><span class="p">.</span><span class="n">tutar</span>
<span class="k">FROM</span> <span class="n">musteriler</span> <span class="k">AS</span> <span class="n">m</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">siparisler</span> <span class="k">AS</span> <span class="n">s</span>
    <span class="k">ON</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">musteri_id</span><span class="p">;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">LEFT JOIN</code>, soldaki <code class="language-plaintext highlighter-rouge">musteriler</code> tablosunun bütün satırlarını korur. Eşleşen sipariş yoksa <code class="language-plaintext highlighter-rouge">siparis_id</code> ve <code class="language-plaintext highlighter-rouge">tutar</code> alanları <code class="language-plaintext highlighter-rouge">NULL</code> görünür. Sipariş vermeyen müşterileri bulmak için bu davranıştan yararlanabiliriz:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span><span class="p">,</span> <span class="n">m</span><span class="p">.</span><span class="n">ad</span>
<span class="k">FROM</span> <span class="n">musteriler</span> <span class="k">AS</span> <span class="n">m</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">siparisler</span> <span class="k">AS</span> <span class="n">s</span>
    <span class="k">ON</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">musteri_id</span>
<span class="k">WHERE</span> <span class="n">s</span><span class="p">.</span><span class="n">id</span> <span class="k">IS</span> <span class="k">NULL</span><span class="p">;</span>
</code></pre></div></div>

<p>Bu sorgu, pazarlama ekibinin “Sepetler neden bu kadar sessiz?” araştırmasına güzel bir başlangıç olabilir.</p>

<h2 id="on-ve-where-tuzağı">ON ve WHERE tuzağı</h2>

<p><code class="language-plaintext highlighter-rouge">LEFT JOIN</code> kullanırken sağ tabloya ait filtreyi <code class="language-plaintext highlighter-rouge">WHERE</code> bölümüne dikkatsizce eklemek, sorguyu fiilen <code class="language-plaintext highlighter-rouge">INNER JOIN</code> gibi davranmaya zorlayabilir:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Siparişi olmayan müşterileri sonuçtan çıkarır</span>
<span class="k">SELECT</span> <span class="n">m</span><span class="p">.</span><span class="n">ad</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">tutar</span>
<span class="k">FROM</span> <span class="n">musteriler</span> <span class="k">AS</span> <span class="n">m</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">siparisler</span> <span class="k">AS</span> <span class="n">s</span> <span class="k">ON</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">musteri_id</span>
<span class="k">WHERE</span> <span class="n">s</span><span class="p">.</span><span class="n">tutar</span> <span class="o">&gt;</span> <span class="mi">1000</span><span class="p">;</span>
</code></pre></div></div>

<p>Eşleşmeyen satırlarda <code class="language-plaintext highlighter-rouge">s.tutar</code> değeri <code class="language-plaintext highlighter-rouge">NULL</code> olduğundan koşul sağlanmaz. Sol tablonun tamamını korumak istiyorsak filtreyi birleştirme koşuluna taşıyabiliriz:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">m</span><span class="p">.</span><span class="n">ad</span><span class="p">,</span> <span class="n">s</span><span class="p">.</span><span class="n">tutar</span>
<span class="k">FROM</span> <span class="n">musteriler</span> <span class="k">AS</span> <span class="n">m</span>
<span class="k">LEFT</span> <span class="k">JOIN</span> <span class="n">siparisler</span> <span class="k">AS</span> <span class="n">s</span>
    <span class="k">ON</span> <span class="n">m</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">musteri_id</span>
   <span class="k">AND</span> <span class="n">s</span><span class="p">.</span><span class="n">tutar</span> <span class="o">&gt;</span> <span class="mi">1000</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="performans-ve-okunabilirlik">Performans ve okunabilirlik</h2>

<p>JOIN sütunlarına indeks eklemek, özellikle büyük tablolarda eşleşme aramasını hızlandırabilir. Ayrıca <code class="language-plaintext highlighter-rouge">SELECT *</code> yerine yalnızca gerekli sütunları seçmek ağ trafiğini ve bellek kullanımını azaltır. Sütun adlarını tablo takma adlarıyla nitelemek de belirsizliği önler.</p>

<p>Özetle, yalnızca karşılıklı eşleşen kayıtlar gerekiyorsa <code class="language-plaintext highlighter-rouge">INNER JOIN</code>; soldaki ana listenin tamamı korunacaksa <code class="language-plaintext highlighter-rouge">LEFT JOIN</code> tercih edilir. Doğru anahtarlar, bilinçli filtreler ve anlaşılır sorgular sayesinde dağınık görünen tablolar anlamlı bir veri hikâyesine dönüşür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="SQL" /><category term="JOIN" /><category term="Veritabanı" /><summary type="html"><![CDATA[Bir e-ticaret sisteminde müşteriler bir tabloda, siparişler başka bir tabloda tutulur. Peki “Hangi müşteri hangi siparişi verdi?” sorusunu nasıl yanıtlarız? SQL dünyasının çöpçatanı JOIN, farklı tablolardaki ilişkili satırları ortak sütunlar üzerinden buluşturur ve sonuçları tek bir sanal tablo gibi sunar.]]></summary></entry><entry><title type="html">Nesne Yönelimli Programlama ile PHP: Sınıflardan Kurumsal Mimariye</title><link href="https://sonsuzus.github.io/posts/nesne-yonelimli-programlama-ile-php-siniflardan-kurumsal-mimariye/" rel="alternate" type="text/html" title="Nesne Yönelimli Programlama ile PHP: Sınıflardan Kurumsal Mimariye" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/nesne-yonelimli-programlama-ile-php-siniflardan-kurumsal-mimariye</id><content type="html" xml:base="https://sonsuzus.github.io/posts/nesne-yonelimli-programlama-ile-php-siniflardan-kurumsal-mimariye/"><![CDATA[<p>PHP ile birkaç sayfalık bir uygulama geliştirirken fonksiyonlar ve değişkenler yeterli görünebilir. Ancak proje büyüyüp kullanıcılar, siparişler, ödemeler ve raporlar devreye girdiğinde kod tabanı hızla spagettiye dönüşebilir. Nesne Yönelimli Programlama, yani OOP, bu karmaşayı gerçek dünyadaki varlıkları sınıflar ve nesneler biçiminde modelleyerek yönetmemizi sağlar.
``</p>

<h2 id="oop-mantığı-sınıf-plan-nesne-üründür">OOP mantığı: Sınıf plan, nesne üründür</h2>

<p>Bir <strong>sınıf</strong>, belirli bir varlığın hangi verilere ve davranışlara sahip olacağını tanımlayan plandır. <strong>Nesne</strong> ise bu plandan oluşturulan somut örnektir. Örneğin <code class="language-plaintext highlighter-rouge">User</code> sınıfı bir mimari proje ise <code class="language-plaintext highlighter-rouge">$ayse</code> ve <code class="language-plaintext highlighter-rouge">$mehmet</code> bu projeye göre inşa edilmiş iki farklı ev gibidir.</p>

<p>Bir sınıfın durumunu özellikler, davranışlarını ise metotlar temsil eder. Bunu matematiksel olarak şöyle düşünebiliriz:</p>

\[Nesne = Durum + Davranış\]

<p>Durum; ad, e-posta veya bakiye gibi verilerden, davranış ise giriş yapma, ödeme gerçekleştirme veya bilgileri güncelleme gibi işlemlerden oluşur.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Görevi</th>
      <th>PHP örneği</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sınıf</td>
      <td>Nesnenin şablonunu tanımlar</td>
      <td><code class="language-plaintext highlighter-rouge">class User</code></td>
    </tr>
    <tr>
      <td>Nesne</td>
      <td>Sınıftan üretilen örnektir</td>
      <td><code class="language-plaintext highlighter-rouge">new User()</code></td>
    </tr>
    <tr>
      <td>Özellik</td>
      <td>Nesnenin verisini tutar</td>
      <td><code class="language-plaintext highlighter-rouge">$email</code></td>
    </tr>
    <tr>
      <td>Metot</td>
      <td>Nesnenin davranışını tanımlar</td>
      <td><code class="language-plaintext highlighter-rouge">login()</code></td>
    </tr>
    <tr>
      <td>Constructor</td>
      <td>İlk değerleri nesneye aktarır</td>
      <td><code class="language-plaintext highlighter-rouge">__construct()</code></td>
    </tr>
  </tbody>
</table>

<h2 id="php-ile-ilk-sınıfımız">PHP ile ilk sınıfımız</h2>

<p>Aşağıdaki sınıf, kullanıcı verisini ve kullanıcıya ait bir davranışı aynı yapı içerisinde toplar:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span>

<span class="kd">class</span> <span class="nc">User</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span>
        <span class="k">private</span> <span class="kt">string</span> <span class="nv">$name</span><span class="p">,</span>
        <span class="k">private</span> <span class="kt">string</span> <span class="nv">$email</span>
    <span class="p">)</span> <span class="p">{}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">getEmail</span><span class="p">():</span> <span class="kt">string</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">email</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">introduce</span><span class="p">():</span> <span class="kt">string</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="s2">"Merhaba, ben </span><span class="si">{</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="n">name</span><span class="si">}</span><span class="s2">."</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nv">$user</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">User</span><span class="p">(</span><span class="s2">"Ayşe"</span><span class="p">,</span> <span class="s2">"ayse@example.com"</span><span class="p">);</span>
<span class="k">echo</span> <span class="nv">$user</span><span class="o">-&gt;</span><span class="nf">introduce</span><span class="p">();</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">__construct()</code> metodu nesne oluşturulurken otomatik çalışır. <code class="language-plaintext highlighter-rouge">private</code> özellikler dışarıdan doğrudan değiştirilemez; böylece nesnenin iç durumu korunur. <code class="language-plaintext highlighter-rouge">$this</code> ise çalışılan mevcut nesneyi ifade eder. Tip bildirimleri sayesinde yanlış veri kullanımı daha erken fark edilir.</p>

<h2 id="oopnin-dört-temel-direği">OOP’nin dört temel direği</h2>

<p>OOP yalnızca kodu sınıflara bölmek değildir. Yaklaşımın arkasında dört önemli ilke bulunur:</p>

<ol>
  <li><strong>Kapsülleme:</strong> Veriyi ve o veriyi işleyen metotları aynı yapıda toplar. İç ayrıntılar dış dünyadan saklanır.</li>
  <li><strong>Kalıtım:</strong> Bir sınıfın özellik ve davranışlarının başka bir sınıfa aktarılmasını sağlar.</li>
  <li><strong>Çok biçimlilik:</strong> Farklı sınıfların aynı arayüz üzerinden farklı davranış göstermesine imkân verir.</li>
  <li><strong>Soyutlama:</strong> Gereksiz ayrıntıları gizleyerek yalnızca kullanılacak sözleşmeyi öne çıkarır.</li>
</ol>

<p>Ödeme sisteminde çok biçimlilik oldukça kullanışlıdır:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">interface</span> <span class="nc">PaymentMethod</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">pay</span><span class="p">(</span><span class="kt">float</span> <span class="nv">$amount</span><span class="p">):</span> <span class="kt">bool</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">CreditCardPayment</span> <span class="kd">implements</span> <span class="nc">PaymentMethod</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">pay</span><span class="p">(</span><span class="kt">float</span> <span class="nv">$amount</span><span class="p">):</span> <span class="kt">bool</span>
    <span class="p">{</span>
        <span class="c1">// Banka servisine ödeme isteği gönderilir.</span>
        <span class="k">return</span> <span class="nv">$amount</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kd">class</span> <span class="nc">BankTransferPayment</span> <span class="kd">implements</span> <span class="nc">PaymentMethod</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">pay</span><span class="p">(</span><span class="kt">float</span> <span class="nv">$amount</span><span class="p">):</span> <span class="kt">bool</span>
    <span class="p">{</span>
        <span class="c1">// Havale kaydı oluşturulur.</span>
        <span class="k">return</span> <span class="nv">$amount</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Her iki sınıf da <code class="language-plaintext highlighter-rouge">PaymentMethod</code> sözleşmesine uyar. Uygulamanın geri kalanı ödemenin kartla mı yoksa havaleyle mi yapıldığını bilmek zorunda değildir. Yeni bir yöntem eklemek, mevcut kodu dağıtıp yeniden toplamaya dönüşmez.</p>

<table>
  <thead>
    <tr>
      <th>Prosedürel yaklaşım</th>
      <th>Nesne yönelimli yaklaşım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Veri ve fonksiyonlar ayrıdır</td>
      <td>Veri ve davranış birlikte modellenir</td>
    </tr>
    <tr>
      <td>Küçük betiklerde pratiktir</td>
      <td>Büyük projelerde daha sürdürülebilirdir</td>
    </tr>
    <tr>
      <td>Bağımlılıklar kolayca karışabilir</td>
      <td>Arayüzlerle bağımlılıklar azaltılabilir</td>
    </tr>
    <tr>
      <td>Değişiklikler birçok dosyayı etkileyebilir</td>
      <td>Sorumluluklar sınıflara dağıtılır</td>
    </tr>
  </tbody>
</table>

<h2 id="kurumsal-projelerde-neden-tercih-edilir">Kurumsal projelerde neden tercih edilir?</h2>

<p>Kurumsal yazılımlar sürekli değişir. Bugün tek ödeme sağlayıcısı kullanan sistem yarın üç farklı sağlayıcıya bağlanabilir. OOP; <strong>SOLID</strong>, katmanlı mimari, bağımlılık enjeksiyonu ve tasarım desenleri gibi yaklaşımlara zemin hazırlar. Laravel ve Symfony gibi PHP framework’lerinin servis, controller, entity ve repository yapıları da bu temele dayanır.</p>

<p>Yine de her şeyi sınıfa çevirmek iyi mimari değildir. Her sınıfın tek ve anlaşılır bir sorumluluğu olmalı; devasa sınıflardan ve gereksiz kalıtımdan kaçınılmalıdır. Amaç daha fazla kod yazmak değil, değişikliğin maliyetini azaltmaktır. İyi modellenmiş bir PHP projesinde sınıflar yalnızca sözdizimi aracı değil, yazılımın iş dünyasını anlatan yaşayan bir haritadır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="PHP" /><category term="OOP" /><category term="Yazılım Mimarisi" /><summary type="html"><![CDATA[PHP ile birkaç sayfalık bir uygulama geliştirirken fonksiyonlar ve değişkenler yeterli görünebilir. Ancak proje büyüyüp kullanıcılar, siparişler, ödemeler ve raporlar devreye girdiğinde kod tabanı hızla spagettiye dönüşebilir. Nesne Yönelimli Programlama, yani OOP, bu karmaşayı gerçek dünyadaki varlıkları sınıflar ve nesneler biçiminde modelleyerek yönetmemizi sağlar.]]></summary></entry><entry><title type="html">Oturum ve Çerez Yönetimi: Güvenli Login/Logout Sistemlerinin Anatomisi</title><link href="https://sonsuzus.github.io/posts/oturum-ve-cerez-yonetimi-guvenli-loginlogout-sistemlerinin-anatomisi/" rel="alternate" type="text/html" title="Oturum ve Çerez Yönetimi: Güvenli Login/Logout Sistemlerinin Anatomisi" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/oturum-ve-cerez-yonetimi-guvenli-loginlogout-sistemlerinin-anatomisi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/oturum-ve-cerez-yonetimi-guvenli-loginlogout-sistemlerinin-anatomisi/"><![CDATA[<p>Bir kullanıcı giriş yaptığında uygulamanın onu sonraki istekte hatırlaması gerekir. HTTP ise doğası gereği durumsuzdur; yani sunucu, arka arkaya gelen iki isteğin aynı kişiye ait olduğunu kendiliğinden bilmez. Oturum ve çerez mekanizmaları bu hafıza problemini çözer. Biri bilgiyi çoğunlukla sunucuda, diğeri tarayıcıda taşır; doğru kullanıldıklarında güvenli ve akıcı bir kullanıcı deneyimi oluştururlar.</p>

<p>``</p>

<h2 id="http-neden-kullanıcıyı-hatırlamaz">HTTP Neden Kullanıcıyı Hatırlamaz?</h2>

<p>Her HTTP isteği bağımsız değerlendirilir. Kullanıcı <code class="language-plaintext highlighter-rouge">/login</code> adresinde doğru parolayı girdikten sonra <code class="language-plaintext highlighter-rouge">/profile</code> sayfasına geçtiğinde tarayıcının kimliğini yeniden kanıtlaması gerekir. Teorik olarak doğrulama maliyetini şöyle düşünebiliriz:</p>

\[T_{toplam} = n \times T_{doğrulama}\]

<p>Her istekte parola doğrulamak yerine ilk doğrulamada bir oturum oluşturulursa yaklaşık maliyet şu hâle gelir:</p>

\[T_{toplam} = T_{login} + n \times T_{sessionKontrolü}\]

<p>Oturum kontrolü, parola özeti hesaplamaktan çok daha hızlıdır. Üstelik parola her istekte ağ üzerinde dolaşmaz.</p>

<h2 id="cookie-ve-session-arasındaki-fark">Cookie ve Session Arasındaki Fark</h2>

<p>Cookie, tarayıcının sakladığı ve uygun isteklerle sunucuya gönderdiği küçük bir anahtar-değer verisidir. Session ise kullanıcıya ait geçici durumun sunucuda saklanmasıdır. Tarayıcı genellikle yalnızca tahmin edilmesi zor bir oturum kimliği taşır.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Cookie</th>
      <th>Session</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Saklama yeri</td>
      <td>Tarayıcı</td>
      <td>Sunucu, Redis veya veritabanı</td>
    </tr>
    <tr>
      <td>Veri kapasitesi</td>
      <td>Yaklaşık 4 KB</td>
      <td>Altyapıya bağlı</td>
    </tr>
    <tr>
      <td>Hassas veri</td>
      <td>Saklanmamalı</td>
      <td>Daha uygun</td>
    </tr>
    <tr>
      <td>Sunucu yükü</td>
      <td>Düşük</td>
      <td>Kullanıcı sayısıyla artar</td>
    </tr>
    <tr>
      <td>Tipik kullanım</td>
      <td>Tema, dil, session ID</td>
      <td>Kullanıcı kimliği, yetkiler</td>
    </tr>
  </tbody>
</table>

<p>Örneğin <code class="language-plaintext highlighter-rouge">theme=dark</code> doğrudan cookie içinde tutulabilir. Ancak <code class="language-plaintext highlighter-rouge">role=admin</code> değerine güvenmek tehlikelidir; kullanıcı tarayıcı araçlarıyla bunu değiştirebilir. Yetki bilgisi sunucuda doğrulanmalıdır.</p>

<h2 id="express-ile-login-ve-logout">Express ile Login ve Logout</h2>

<p>Aşağıdaki örnek, oturum verisini sunucuda tutar ve tarayıcıya yalnızca oturum kimliğini içeren cookie gönderir:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">express</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">express</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">session</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">express-session</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">bcrypt</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">bcrypt</span><span class="dl">"</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nf">express</span><span class="p">();</span>
<span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nf">json</span><span class="p">());</span>

<span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nf">session</span><span class="p">({</span>
  <span class="na">secret</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">SESSION_SECRET</span><span class="p">,</span>
  <span class="na">resave</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
  <span class="na">saveUninitialized</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
  <span class="na">cookie</span><span class="p">:</span> <span class="p">{</span>
    <span class="na">httpOnly</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
    <span class="na">secure</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">production</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">sameSite</span><span class="p">:</span> <span class="dl">"</span><span class="s2">lax</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">maxAge</span><span class="p">:</span> <span class="mi">1000</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">30</span>
  <span class="p">}</span>
<span class="p">}));</span>

<span class="nx">app</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">"</span><span class="s2">/login</span><span class="dl">"</span><span class="p">,</span> <span class="k">async </span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">user</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">findUserByEmail</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">email</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">valid</span> <span class="o">=</span> <span class="nx">user</span> <span class="o">&amp;&amp;</span> <span class="k">await</span> <span class="nx">bcrypt</span><span class="p">.</span><span class="nf">compare</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">password</span><span class="p">,</span> <span class="nx">user</span><span class="p">.</span><span class="nx">passwordHash</span><span class="p">);</span>

  <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">valid</span><span class="p">)</span> <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nf">status</span><span class="p">(</span><span class="mi">401</span><span class="p">).</span><span class="nf">json</span><span class="p">({</span> <span class="na">error</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Geçersiz bilgiler</span><span class="dl">"</span> <span class="p">});</span>

  <span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nf">regenerate</span><span class="p">(</span><span class="nx">error</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nf">sendStatus</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nx">userId</span> <span class="o">=</span> <span class="nx">user</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span>
    <span class="nx">res</span><span class="p">.</span><span class="nf">json</span><span class="p">({</span> <span class="na">message</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Giriş başarılı</span><span class="dl">"</span> <span class="p">});</span>
  <span class="p">});</span>
<span class="p">});</span>

<span class="nx">app</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">"</span><span class="s2">/logout</span><span class="dl">"</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">req</span><span class="p">.</span><span class="nx">session</span><span class="p">.</span><span class="nf">destroy</span><span class="p">(</span><span class="nx">error</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">if </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nf">sendStatus</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="nx">res</span><span class="p">.</span><span class="nf">clearCookie</span><span class="p">(</span><span class="dl">"</span><span class="s2">connect.sid</span><span class="dl">"</span><span class="p">);</span>
    <span class="nx">res</span><span class="p">.</span><span class="nf">sendStatus</span><span class="p">(</span><span class="mi">204</span><span class="p">);</span>
  <span class="p">});</span>
<span class="p">});</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">httpOnly</code>, JavaScript’in cookie değerini okumasını engelleyerek XSS saldırılarının etkisini azaltır. <code class="language-plaintext highlighter-rouge">secure</code>, cookie’nin yalnızca HTTPS üzerinden gönderilmesini sağlar. <code class="language-plaintext highlighter-rouge">sameSite</code>, başka sitelerden başlatılan istekleri sınırlayarak CSRF riskini düşürür. Login sonrasında <code class="language-plaintext highlighter-rouge">regenerate</code> kullanılması ise saldırganın önceden bildiği bir kimliği kurbana kullandırdığı session fixation saldırısına karşı önemlidir.</p>

<h2 id="tercihler-nerede-saklanmalı">Tercihler Nerede Saklanmalı?</h2>

<table>
  <thead>
    <tr>
      <th>Veri</th>
      <th>Önerilen yer</th>
      <th>Gerekçe</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tema ve dil</td>
      <td>Cookie veya localStorage</td>
      <td>Hassas değildir</td>
    </tr>
    <tr>
      <td>Sepet kimliği</td>
      <td>İmzalı cookie/session</td>
      <td>Bütünlük gerekir</td>
    </tr>
    <tr>
      <td>Kullanıcı ID</td>
      <td>Session</td>
      <td>İstemciye güvenilmez</td>
    </tr>
    <tr>
      <td>Parola</td>
      <td>Hiçbiri</td>
      <td>Yalnızca hash saklanır</td>
    </tr>
    <tr>
      <td>Erişim yetkileri</td>
      <td>Sunucu</td>
      <td>Her istekte doğrulanmalıdır</td>
    </tr>
  </tbody>
</table>

<p>Gerçek projelerde varsayılan bellek tabanlı session deposu kullanılmamalıdır; süreç yeniden başlayınca oturumlar kaybolur ve birden fazla sunucu arasında paylaşılmaz. Redis gibi süre sonu destekleyen merkezi bir depo daha uygundur.</p>

<p>Son olarak logout yalnızca arayüzde kullanıcıyı giriş sayfasına göndermek değildir. Sunucudaki oturum gerçekten yok edilmeli, cookie temizlenmeli ve hassas işlemlerde gerekirse tüm cihazlardaki oturumları iptal edebilmek için kullanıcı bazlı bir oturum listesi tutulmalıdır. Kısacası iyi bir giriş sistemi, kapıyı açmayı bildiği kadar kapatmayı da bilmelidir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="session" /><category term="cookie" /><category term="kimlik doğrulama" /><summary type="html"><![CDATA[Bir kullanıcı giriş yaptığında uygulamanın onu sonraki istekte hatırlaması gerekir. HTTP ise doğası gereği durumsuzdur; yani sunucu, arka arkaya gelen iki isteğin aynı kişiye ait olduğunu kendiliğinden bilmez. Oturum ve çerez mekanizmaları bu hafıza problemini çözer. Biri bilgiyi çoğunlukla sunucuda, diğeri tarayıcıda taşır; doğru kullanıldıklarında güvenli ve akıcı bir kullanıcı deneyimi oluştururlar.]]></summary></entry><entry><title type="html">Oyun Teorisinden Minimax’a: İki Oyunculu Oyunlarda Kazanma Stratejisi</title><link href="https://sonsuzus.github.io/posts/oyun-teorisinden-minimaxa-iki-oyunculu-oyunlarda-kazanma-stratejisi/" rel="alternate" type="text/html" title="Oyun Teorisinden Minimax’a: İki Oyunculu Oyunlarda Kazanma Stratejisi" /><published>2026-08-06T00:00:00+00:00</published><updated>2026-08-06T00:00:00+00:00</updated><id>https://sonsuzus.github.io/posts/oyun-teorisinden-minimaxa-iki-oyunculu-oyunlarda-kazanma-stratejisi</id><content type="html" xml:base="https://sonsuzus.github.io/posts/oyun-teorisinden-minimaxa-iki-oyunculu-oyunlarda-kazanma-stratejisi/"><![CDATA[<p>Satrançta rakibin vezirini tehdit ettiğinde neden hemen sevinmemelisin? Çünkü rakibin de plan yapıyor! Oyun teorisi, kararlarımızın sonucunun yalnızca bize değil, başka oyuncuların seçimlerine de bağlı olduğu durumları matematiksel olarak inceler. Minimax algoritması ise bu fikirleri bilgisayarların anlayabileceği bir oyun ağacına dönüştürerek mümkün olan en güvenli hamleyi seçmelerini sağlar.
``</p>

<h2 id="oyun-teorisinin-temel-bileşenleri">Oyun teorisinin temel bileşenleri</h2>

<p>Bir oyun; <strong>oyuncular</strong>, oyuncuların seçebileceği <strong>stratejiler</strong>, oyunun mevcut <strong>durumu</strong> ve sonuçları değerlendiren <strong>kazanç fonksiyonundan</strong> oluşur. İki oyunculu sıfır toplamlı bir oyunda bir tarafın kazancı, diğer tarafın kaybıdır. Kazançlar $u_1$ ve $u_2$ ile gösterilirse:</p>

\[u_1 + u_2 = 0\]

<p>Satranç, dama ve tic-tac-toe bu modele oldukça uygundur. Bu oyunlarda oyuncular sırayla hareket eder, oyun durumu herkes tarafından görülür ve şans faktörü bulunmaz. Böyle oyunlara <strong>deterministik, tam bilgili oyunlar</strong> denir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Açıklama</th>
      <th>Tic-tac-toe örneği</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Durum</td>
      <td>Oyunun belirli andaki görünümü</td>
      <td>Tahtadaki X ve O işaretleri</td>
    </tr>
    <tr>
      <td>Hamle</td>
      <td>Bir durumdan diğerine geçiş</td>
      <td>Boş hücreye X koymak</td>
    </tr>
    <tr>
      <td>Terminal durum</td>
      <td>Oyunun sona erdiği durum</td>
      <td>Kazanma veya beraberlik</td>
    </tr>
    <tr>
      <td>Fayda değeri</td>
      <td>Sonucun sayısal karşılığı</td>
      <td>Kazanma: $1$, beraberlik: $0$, kayıp: $-1$</td>
    </tr>
  </tbody>
</table>

<h2 id="minimax-nasıl-düşünür">Minimax nasıl düşünür?</h2>

<p>Minimax algoritmasında bir oyuncuya <strong>MAX</strong>, diğerine <strong>MIN</strong> adı verilir. MAX en yüksek skoru seçmeye, MIN ise bu skoru mümkün olduğunca düşürmeye çalışır. Algoritma, rakibin hata yapacağını ummaz; tam tersine, rakibin her zaman en iyi hamleyi oynayacağını varsayar. Biraz karamsardır ama hazırlıksız yakalanmaz!</p>

<p>Bir $s$ durumu için minimax değeri şöyle tanımlanabilir:</p>

\[V(s) = \max V(s') \quad \text{MAX sırasındaysa}\]

\[V(s) = \min V(s') \quad \text{MIN sırasındaysa}\]

<p>Buradaki $s’$, mevcut durumdan ulaşılabilen çocuk durumlardan biridir. Terminal durumda ise değer doğrudan kazanç fonksiyonundan alınır.</p>

<h2 id="python-ile-minimax-uygulaması">Python ile minimax uygulaması</h2>

<p>Aşağıdaki fonksiyon, önceden oluşturulmuş bir oyun ağacını dolaşır. Yaprak düğümler sayısal sonuçları, listeler ise olası hamleleri temsil eder:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">minimax</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">maximizing</span><span class="p">):</span>
    <span class="c1"># Sayıya ulaştıysak oyun bitmiştir.
</span>    <span class="k">if</span> <span class="nf">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">node</span>

    <span class="n">scores</span> <span class="o">=</span> <span class="p">[</span><span class="nf">minimax</span><span class="p">(</span><span class="n">child</span><span class="p">,</span> <span class="ow">not</span> <span class="n">maximizing</span><span class="p">)</span> <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">node</span><span class="p">]</span>

    <span class="c1"># MAX en büyük, MIN en küçük sonucu seçer.
</span>    <span class="k">return</span> <span class="nf">max</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span> <span class="k">if</span> <span class="n">maximizing</span> <span class="k">else</span> <span class="nf">min</span><span class="p">(</span><span class="n">scores</span><span class="p">)</span>

<span class="c1"># MAX oyuncusunun üç farklı hamlesi
</span> <span class="n">game_tree</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">9</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">]</span>
<span class="p">]</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">minimax</span><span class="p">(</span><span class="n">game_tree</span><span class="p">,</span> <span class="bp">True</span><span class="p">))</span>  <span class="c1"># Çıktı: 6
</span></code></pre></div></div>

<p>MIN her dalda en düşük değeri seçeceği için dalların değerleri sırasıyla $2$, $1$ ve $6$ olur. MAX da bunların en büyüğü olan $6$ değerli üçüncü hamleyi tercih eder. Böylece karar formülü $\max(2,1,6)=6$ olur.</p>

<h2 id="kazanma-stratejisi-nasıl-hesaplanır">Kazanma stratejisi nasıl hesaplanır?</h2>

<p>Öncelikle geçerli tüm hamleler üretilir ve her hamle için oluşacak durum hesaplanır. Oyun sonuna ulaşılabiliyorsa gerçek fayda değeri kullanılır. Satranç gibi ağacı devasa olan oyunlarda ise belirli bir derinlikte durularak taş üstünlüğü, hareketlilik ve şah güvenliği gibi ölçütlerden oluşan bir <strong>sezgisel değerlendirme fonksiyonu</strong> çalıştırılır.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tam minimax</td>
      <td>Kesin sonucu bulabilir</td>
      <td>Büyük ağaçlarda çok yavaştır</td>
    </tr>
    <tr>
      <td>Derinlik sınırlı minimax</td>
      <td>Daha hızlıdır</td>
      <td>Değerlendirme hatası yapabilir</td>
    </tr>
    <tr>
      <td>Alfa-beta budama</td>
      <td>Gereksiz dalları atlar</td>
      <td>Hamle sıralamasına duyarlıdır</td>
    </tr>
  </tbody>
</table>

<p>Alfa-beta budama, sonucu değiştirmeyeceği kesinleşen dalları incelemez. İyi bir hamle sıralamasıyla minimax’ın pratik performansını ciddi biçimde artırır. Sonuç olarak kazanma stratejisi; rakibin en güçlü cevabını hesaba katmak, en kötü sonucu güvenceye almak ve hesaplama sınırları varsa durumları doğru değerlendirmek üzerine kuruludur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="oyun teorisi" /><category term="minimax" /><category term="algoritma" /><summary type="html"><![CDATA[Satrançta rakibin vezirini tehdit ettiğinde neden hemen sevinmemelisin? Çünkü rakibin de plan yapıyor! Oyun teorisi, kararlarımızın sonucunun yalnızca bize değil, başka oyuncuların seçimlerine de bağlı olduğu durumları matematiksel olarak inceler. Minimax algoritması ise bu fikirleri bilgisayarların anlayabileceği bir oyun ağacına dönüştürerek mümkün olan en güvenli hamleyi seçmelerini sağlar.]]></summary></entry></feed>