PHP dosyanıza resim (dosya) gömmek

Dikkat: Bu yazının yazılma tarihinin üzerinden en az 60 gün geçmiş. İçerisindeki bilgiler güncelliğini yitirmiş olabilir. Yorumları ve güncellemeleri göz önünde bulundurarak yazıyı takip ediniz.

Böyle birşeye neden ihtiyaç duyarsınız?

En büyük nedeni, tek dosyadan oluşan bir script yazıyor olabilirsiniz (konuyla ilgili olarak PHP ile tek dosyadan oluşan proje üretmek dökümanını okuyabilirsiniz). Ya da yazdığınız projede kullandığınız ufacık ikonların bir sürü dosya şeklinde durmasını istemiyor olabilirsiniz. Başka bir tercih de dosyalarınızı bir veritabanında tutuyormuşcasına tek dosyada depolamak isteyebilirsiniz. Çok küçük boyutlu resimler için bahsettiğim konu daha yaygın kullanılır.

Yani yazdığınız betik kendi içindeki css kuralları ile şekillendirilmiş, ikonlarla da güçlendilirmişse ve ikonlar için ek dosyalar koymak istemiyorsanız bu yöntemi kullanabilirsiniz.

Teknik

Aslında yapılan iş oldukça basit. Öncelikle dosyalarımızı php dosyamızın içine nasıl gömeceğiz? PHP dosyalarımız ascii dosyalar, binary içeriği alabilmek ve saklayabilmek için base64 ile şifreleyeceğiz. Sonuçta ortaya çıkacak olan şey bir ascii şifre olacaktır. Dosya boyutuna göre bu şifrenin uzunluğu artacaktır. Unutmayın ki bu anlattığım yöntem tamamen ufak dosyaları gömmek içindir 100kb üzeri dosyaları php dosyanıza gömerseniz, ya da php dosyanızın boyutu megabyte'ları aştığı zaman işlenmesi zorlaşacaktır. Birkaç ufak dosya için kullandığınız sürece verimli olacaktır.

Dosyalarımız encode etmek için bir kod kullanacağız. Bu işlemi başka bir php dosyası oluşturarak yapın.
<?php

$dosya = 'resim.gif';

// dosya icerigini okuyalim
$dosya_binary = fopen($dosya, "r");
$icerik_binary = fread($dosya_binary, filesize($dosya));
fclose($dosya_binary);

// binary icerigi ascii'ye base64 ile cevirelim
$icerik_ascii = base64_encode($icerik_binary);

print $icerik_ascii;

?>
Bu kod resim.gif dosyasını ekrana ascii karakterlerle şifrelenmiş şekilde uzun bir metin şeklinde basacaktır. Bu metini kopyalayarak kullanacağız ve orjinal proje dosyamız şöyle olacak
// dosyalar
$dosyalar["resim.gif"] = "R0lGODlhEAAQAMQAAGZmZsbGxaSko4OEgxl4ueT//3G59ejo6Lu7u9zd3".
                         "DOMxXp6eqjU/5mZmX+RmdPU1LKzsfb29v///3u75a2tpY6OjczMzDqPz6".
                         "ysq////wAAAAAAAAAAAAAAAAAAAAAAACH5BAUUABkALAAAAAAQABAAAAW".
                         "JYIaNJDlNWZpiUuu2U4GqrHPd+MTItHQZEoPQoNvNWISkkjBROBUpgQQT".
                         "qVojj6wgOg0IAAEAQBBgbTMNiSCRALDDCWkjlRYcDoBD+C5PVSQNCAgAg".
                         "wKCaRV+gBZfYWIWiCkDEhVslpZ/AykLlBCen55/C5sSAw2nqKeToxmcL6".
                         "8trAuztLW1GSEAOw==";
Yukarıda gördüğünüz şey aslında çok uzun bir string. Yani o satırlar yan yana bitişik fakat ben bu dökümanda açıkca görülebilmesi için bu hale getirdim. Bu gördüğünüz string 258 byte'lık 16x16'lık bir ikonun base64 şifresidir. 258 byte'ın bu kadar sürdüğünü düşünürseniz 10-20kb'lık bir dosyanın ne kadar uzun süreceğini tahmin edebilirsiniz. Onun için büyük dosyalarınızı php dosyanıza gömmeyin.

Yukarıdaki şekilde tüm dosyalarınızı base64_encode'dan geçirip $dosyalar dizisine dosyanın adını taşıyan indiste yazın.
Unutmayın bu dizi proje dosyanızın en üstünde tanımlanmalı. Yani proje dosyanızın içinde her türlü işlemi yapıyor olabilirsiniz ama bu teknikteki kodlar dosyanın en üstünde durmalı.

Neyse, dosyalarınızı $dosyalar dizisine kendi adları indis olacak şekilde kaydettiniz. php dosyanızın boyutu kabardı farkındaysanız (kontrol ediniz). Şimdi bu tanımların ardına ufak bir kod ile işlemi bitireceğiz.
if( $_GET["islem"] == 'dosya' ){
  if( array_key_exists($_GET["dosya"], $dosyalar) ){
    die( base64_decode( $dosyalar[ $_GET["dosya"] ] ) );
  }else{
    die("Dosya bulunamadı!");
  }
}

// projenizin normal işlemlerini bu satırdan sonra
// yapabilirsiniz.
Eğer get methodu ile islem değişkeni dosya olarak gelmişse ve get methodu ile dosya değişkeninin içeriği bizim $dosyalar dizisinde indis olarak varsa $dosyalar dizisindeki o elemanın içeriğini base64_decode edip ekrana basıyoruz. Yoksa dosya bulunamadı hatası verip duruyoruz.

Nasıl kullanacaksınız?

Projenin devamındaki bir kısımda
<img src="index.php?islem=dosya&dosya=resim.gif" ...>
şeklinde kullandığınızda dosyanız resim olarak görüntülenecektir. Aynı şeyi bir arşiv dosyası için de yapabilirsiniz.
<a href="index.php?islem=dosya&dosya=kurulum_dokumani.pdf">Dosyayı indirmek için tıklayın</a>
gibi.

Dosya deposu

Yukarıdaki kodları ayrı bir dosya olarak kaydedip dosyalarınızı tek parça hale getirdiğiniz bir veritabanı gibi düşünebiliriz. Yani
<?php
// dosyalar
$dosyalar["..."] = "....";
$dosyalar["..."] = "....";

// gosterelim
if( array_key_exists($_GET["dosya"], $dosyalar) ){
  die( base64_decode( $dosyalar[ $_GET["dosya"] ] ) );
}else{
  die("Dosya bulunamadı!");
}

?>
Bu dosyaya goster.php, resimler.php veya indir.php diyebilirsiniz. Kullanırken yukarıda index.php olarak gösterdiğimiz yola dosyanızın adını yazın. Ayrıca islem=dosya parametresine de gerek kalmadı çünkü bu dosya zaten sadece bu işi yapıyor :-)


Çok fazla işinize yarar mı bilmiyorum ama yine de bazı yerlerde kullanılan bir teknik olduğu için paylaşma gereği duydum. Umarım faydası dokunur.


Hazırlayan : Mehmet Fatih YILDIZ

Yorumlar

21 Şubat Perşembe ´08 23:30
ilk olrak çok teşekkür ediyorum bu konu için 2 olarak direk resimleri data url method ile kullanmak daha mantıklı bunun için Data Url Resim yardımcısını kullanabilirsiniz adress

http://stats.titag.com/css/31/Tools/data_url.php
23 Şubat Cumartesi ´08 13:14
evet güzel araç yazmışsın eline sağlık.
fakat ie'de bu yöntemi kullanamıyorsun. yani crossbrowser olayını geçersek tabiki html'e gömmek de mantıklı.
Üye Resmi enver
24 Şubat Pazar ´08 00:23
daha önce bu yöntemi yapmış olduğum bir emlak portalında kullanmıştım, kullanımı biraz uğraştırıcı ama güzel bir depolama yöntemi.
Üye Resmi dpa
29 Ağustos Cuma ´08 14:35
güzel anlatmissiniz, elinize saglik. Bir konuda yardiminizi isteyebilirmiyim;RTF yazi grubunu resim olarak ekrana bastirip, boyutlarini hesaplayabilecegim ( mm olarak ) bir olayi nasil kodlayabilirim. tesekkürler ve iyi calismalar
Üye Resmi kadime
25 Kasım Salı ´08 12:34
Sayın Mehmet Fatih YILDIZ; sizden bir ricam var. Joomla ile bir site yaptım (henüz yayımda değil) sitede pdf dökümanlar var, bu dökümanlar embbed olsun ve ayrıca printout, save, save as, save a copy, sağ klik gibi özelliklerinin kapalı olmasını istiyorum. Bunun için nasıl bir kod yazılmalı. Yardımcı olursanız çok sevinirim, teşekkürler.
27 Kasım Perşembe ´08 17:53
Özür dilerim hazır kodlar hakkında çok fazla bilgim yok ve bu konuda destek de vermiyorum. Sadece wordpress ile ilgili çok ufak bilgiye sahibim.

Ayrıca söylediğiniz konu tahminimce oldukça spesifik bir konu. Sanırım flash pdf viewer'lardan birisini modifiye ederek br player oluşturabilirsiniz.
Üye Resmi Aytuğ
3 Eylül Perşembe ´09 23:37
Mehmet hocam merhabalar;
1 sene geciktim bu entry için bu yüzden çok özür dilerim;
Yukarıdaki anlattığınız ders için aynı şekilde farklı dosyaları (php dahil) ekleyebildiğimizi duymuştum ("http://mfyz.com/?/dokuman/101/tek-dosyali-projeler-siteler-uretmek/" burdaki gibi değil tabiiki XD) (base64'e encode edip bir $_GET işlemiyle çözdürüp kullanmak gibi) şimdi benim elimde bir başkasının yazdığı 4 php dosyası ve 3 ufak resimden oluşan ufak bir script var (Server to Server Transfer) bunu tek dosya haline yine sizin anlattığınız gibi getirdim; diğer php'lerin kullanıldığı yerde (ör: download.php?do=1) işlemimi (index.php?islem=dosya&dosya=download.php?do=1) şekline getirdim ama sürekli hata almaktayım (unexpected $dosyalar) gibi yada boş sayfa..  sizce sorun ne olabilir?

(Bu arada bu güne kadar gördüğüm en mükemmel blog yazılımı %100 el yapımı olması ayrı bir kutlama gerektiriyor gerçi ödülü almışsınız ama ben yine tekrar sizi gönülden kutlamak istiyorum)
4 Eylül Cuma ´09 01:13
hata tipi Notice mi Warning mi Fatal Error mu? çünkü bu sanki Notice imiş gibi gelidi bana. Bir de hatanın tümünü buraya yazabilir misin?
Üye Resmi Aytuğ
4 Eylül Cuma ´09 18:31
hızlı cevap için çok teşekkür ederim; Hata warning şeklinde daha önce Parse error şeklinde unexpected $dosyalar blalbla hatası alıyordum şimdi neden o hatayı aldığımı dahi hatırlamıyorum kayboldum XD
her dosyayı ayrı ayrı uğraşmayım diye yukarıda verdiğiniz kodların tümünü birleştirdim (http://www.b4us.co.cc/gom.tar.gz) gerçi neden sadece local'de çalışıyor hiç bir fikrim yok XD
bu script ile aldığım sonucu php'min en başına ekliyorum ve daha sonra downloader.php'nin kullanıldığı her yeri "getfile.php?islem=dosya&dosya=downloader.php" şeklinde değiştiriyorum
ama yeni hata;
Warning: require_once(/GetFile/b/a/getfile.php?islem=dosya&dosya=downloader.php) [function.require-once]: failed to open stream: No such file or directory in C:\wamp\www\GetFile\b\a\getfile.php on line 426

Fatal error: require_once() [function.require]: Failed opening required '/GetFile/b/a/getfile.php?islem=dosya&dosya=downloader.php' (include_path='.;C:\php5\pear') in C:\wamp\www\GetFile\b\a\getfile.php on line 426

şeklinde..
Üye Resmi Aytuğ
4 Eylül Cuma ´09 18:41
bu arada;

7.if( array_key_exists($_GET["dosya"], $dosyalar) ){
8.  die( base64_decode( $dosyalar[ $_GET["dosya"] ] ) );
9.}else{
10.  die("Dosya bulunamadı!");
11.}

kodunda 8. satır niyr die???
kaldırdığımda yani;

7.if( array_key_exists($_GET["dosya"], $dosyalar) ){
8.  base64_decode( $dosyalar[ $_GET["dosya"] ]);
9.}else{
10.  die("Dosya bulunamadı!");
11.}

şeklinde kullandığımdA yine bişey darketmiyor ama...
dosyayı getfile.php?islem=dosya&dosya=downloader.php şeklinde çağırdığımda da ekrana dosya bulunamadı yazdırıyor...
4 Eylül Cuma ´09 21:38
$dosyalar dizisine o "downloader.php" dosyasının base64 edilmiş halini koydun mu?

die'ı kaldırırsan ekrana basılmaz. Zaten şu an o satırlar işletilmiyor söylediğin hataya göre.
4 Eylül Cuma ´09 22:18
tabiiki koydum eğer incelediysenizhttp://www.b4us.co.cc/gom.tar.gz (içinde iki tane dosya var encode.php ve gom.php ikiside aynı görevi yapıyor, önce encodu yaptım hostta çalışmadı upload etmio herhalde diye emin olmak için gom.php'yi yaptım yine hostta çalışmadı ama local'de gayet iyi çalışıyor) adresindeki script'i script yukarda verdiğinizi otomatik olarak yapıyor zaten, kendim her seferinde dikkat edemeyebilirim gözümden kaçırdığım yerler olur diye oluşturdum; neyse.. sorun o ki
$dosyalar["downloader.php"] = "PD9waHANCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8....."; şeklinde list'im var, hemen altında
if( $_GET["islem"] == 'dosya' ){
  if( array_key_exists($_GET["dosya"], $dosyalar) ){
.... şeklinde get'im var,
ammavelakin bi şekilde dönmüyor.. ilgilenmek isterseniz direkt olarak script'i sıkıştırıp upload edeyim bakın. ama sizi de meşgul etmek istemiyorum. ilgilendiğiniz için ve sıradaki cevap için şimdiden teşekkür ederim   :-D
4 Eylül Cuma ´09 22:36
Çok özür dileyerek blog'da bir daha kalabalık yaratıyorum..(blog mükemmel, edit olsa bu kadar ezilip incelmezdim karşınızda XD)
die() aynı exit() gibi scriptten çıkış alıyodu diye hatırlıyorum, henüz başaramadım ekrana bastırmayı ama eval kullanmıyormuyduk bunun için?
6 Eylül Pazar ´09 15:03
Koyduğun dosya içinde base64 edilmiş bir dosya içeriği göremedim. Sanırım senin anladığın şey ile benim burada anlattığım şey farklı. Dosyaların binary de olsa, ascii de olsa (.php dosyaları gibi) base64 edip oyle koyman gerekiyor diziye.
6 Eylül Pazar ´09 15:47
Hocam;
ben o dosya içerisinde bace64 encode edilmiş bir dosya içeriği var demedim o dosya sizin yukarda verdiğiniz kodları otomatik olarak yapıyor dedim, bunuda her seferinde uğraşmayım diye yaptığımı söyledim kodu yorumlasaydınız farkederdiniz sanırım sadece gözünüz encode edilmiş bi array list aradı.. benim upload ettiğim o dosya vereceğiniz bir dosyayı base64 encode ediyor, bunu $dosyalar["DOSYA_ADI"] şeklinde listeliyor, altınada $_GET kodunu yazıyor... 2 entry öncenin en sonunda "ilgilenmek isterseniz direkt olarak script'i sıkıştırıp upload edeyim bakın." demiştim, ama tekrar tekrar söylüyorum sizi uğraştırmak da istemiyorum.. Kısaca benim downloader.php'yi yukarıda verdiğim script ile açınca getgile.php içerisine yazmam gereken kodları veriyor bende yazıyorum ama getfile.php?dosyalar=downloader.php dosya bulunamadı olarak çıkış alıyor... bu server2server script'i dışında başka bir şeyde denemedim henüz, deneyince burada yazarım ki sorunu çözdüğümdede hatamın nerde olduğunu yazarım mutlaka benim gibi bir hataya düşen arkadaşlar olacaktır yardımcı olur.. Tekrar teşekkür eder iyi çalışmalar dilerim..
21 Mart Pazar ´10 02:41
Bu makaleden uzan süren yorumları okuduğumda hala birşeyler yapmak için ve geliştirmek için ve sorgulayan bir nesil görüyorum ve bu benim çok hoşuma gitti. Tebrikler Arkadaşlar ve teşekkürler Mehmet abi.
Üye Resmi Adem
27 Ekim Cumartesi ´12 15:23
Öne şunu söyleyim bu site bende firefox kullanıyorum çok kasıyor kaskat kesiliyor betik durdur yapıyorum ama yanı 20 metre resim veya video dolu sayfa nasıl hareket etmekte zorlanır buda aynı bilginize.

Ben bunu şöyle kullanmak istiyorum ama yapamadım
Upload ile resmi gönderip veritabanına base64_encode olarak kaydedip sonra bir sayfada bu küçük resmi göstermek.

Amacım şunun için web sayfa bilgisayara farklı kaydet ile kaydedildiğinde resim göstermeye devam etmesi için

$icerik_ascii bu değişkenden gelen kodu veritabanına kaydettim ama sayfada göstermek için GET POST işleri ile işim yok ama nasıl yapacağım
Yeni Yorum *
İletişim Bilgileri
*
*
E-Posta adresiniz gösterilmeyecektir.
(unut)
Güvenlik Kodu *

Gönderiliyor