Google Gemini, Google'ın son teknoloji ürünü yapay zeka sistemi olarak karşımıza çıkıyor. Konuşma tabanlı yapay zeka alanında etkileyici bir ilerleme sunan bu sistem, kullanıcılarla etkileşim kurarak doğal dil anlayışını kullanıyor. Sesli asistanlar, metin tabanlı sohbetler ve daha birçok alanda Google Gemini'nin potansiyeli oldukça geniş.
Bu yeni ürün, gerçek zamanlı çeviri, sesli komutlar üzerinden işlem yapma, derin öğrenme tekniklerini kullanarak kişiselleştirilmiş deneyimler sunma gibi özelliklerle dikkat çekiyor. Ayrıca, Google'ın geniş veri havuzunu kullanarak daha hızlı ve doğru cevaplar üretebileceği konuşuluyor.
Google official hesabı üzerinden paylaşılan videoda Google CEO'su Sundar Pichai, "Gemini, sıfırdan modüler olacak şekilde programlandı; Bu, metin, kod, ses, görüntü ve video dahil olmak üzere farklı türdeki bilgileri genelleştirebileceği ve kusursuz bir şekilde anlayabileceği, bunlar üzerinde çalışabileceği ve birleştirebileceği anlamına geliyor." söyledi.
ChatGPT: Yapay Zeka Dünyasının ÖncülerindenÖte yandan, OpenAI tarafından geliştirilen ChatGPT, doğal dil işleme ve anlama konusunda öncü bir yapay zeka sistemidir. Çeşitli dil becerilerine sahip olan bu sistem, metin tabanlı etkileşimlerde insan benzeri cevaplar üretebilir. ChatGPT, geniş veri setlerine dayalı olarak esneklik ve çok yönlülük konusunda dikkat çeker.
ChatGPT'nin gücü, geniş bir dil yelpazesi ve derin öğrenme modelleriyle kullanıcıların çeşitli konularda etkileşimde bulunabilmesine olanak tanımasıdır. İnsan benzeri sohbetler, metin üretimi ve hatta bazı durumlarda yaratıcı içerik oluşturma yetenekleri, ChatGPT'nin benzersiz özellikleri arasında yer alır.
Google Gemini ve ChatGPT Karşılaştırması: Hangisi Daha İyi?Google Gemini ve ChatGPT, yapay zeka alanında farklı yaklaşımlar sunar. Google Gemini, Google'ın geniş veri havuzundan faydalanarak hızlı ve gerçek zamanlı çözümler sunma potansiyeline sahiptir. Öte yandan, ChatGPT, dilin derinliklerine inerek daha esnek ve geniş bir dil yelpazesi sunar.
Hangi sistem daha iyi olduğu, kullanım senaryolarına ve beklentilere bağlı olarak değişebilir. Google Gemini, belirli işlevlerde hızlı çözümler sunarken, ChatGPT daha geniş bir dil yelpazesi ve esneklik sunabilir. İşlevsellik, kişiselleştirme ve günlük kullanım bağlamında tercihler değişebilir.
Sonuç: Yapay Zeka Rekabetinde Yolculuk Devam EdiyorGoogle Gemini ve ChatGPT gibi yapay zeka sistemleri, teknoloji dünyasında devrim niteliğinde adımlar atıyor. Bu sistemler, doğal dil işleme ve anlama konusunda insan benzeri yetenekler sunarak gelecekteki teknoloji trendlerini şekillendirme potansiyeline sahip.
Hangi sistem tercih edilirse edilsin, yapay zeka teknolojilerinin gelişimi ve rekabeti, kullanıcılar için daha iyi ve daha akıllı bir gelecek vaat ediyor. Bu rekabet, daha yenilikçi ve kullanıcı odaklı yapay zeka sistemlerinin ortaya çıkmasına olanak tanıyarak, teknoloji dünyasında heyecan verici bir yolculuğun başlangıcını işaret ediyor.
]]>Bu makalemizde, "EADDRINUSE: address already in use" hatası ile karşılaştığınızda sorunu Windows, Linux ve Mac işletim sistemlerinde çalışan cihazlarda nasıl giderebileceğinizi paylaşacağız.
MAC ve Linux İşletim Sisteminde:lsof -i tcp:port_number
Komutta kullanılan "port_number" belirli bir port numarası olmalıdır. Bu komut, belirli bir portu kullanan işlemi görüntüler. Terminalde sorgulama sonrası aşağıdaki şekilde bir çıktı terminalde görüntülenecektir.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 12345 chen5 31u IPv4 0x8b1721168764e4bf 0t0 TCP *:strexec-s (LISTEN)
Listelenen satırda PID altında görüntülenen numarayı "process_id" alanına yazıp komutu çalıştırınız.
kill -9 process_id
İşlemin hızlı bir şekilde sorunsuz kill edileceğinden emin olmak için -9 komutunu kullanabilirsiniz. Örneğin, "sudo kill -9 1234" komutunu kullanarak 1234 kimlik numaralı bir işlemi sonlandırabilirsiniz.
Windows İşletim Sisteminde:netstat -ano | findstr :port_number
Komutta kullanılan "port_number" belirli bir port numarası olmalıdır. Bu komut, belirli bir portu kullanan işlemi görüntüler. Terminalde sorgulama sonrası aşağıdaki şekilde bir çıktı terminalde görüntülenecektir.
Proto Local Address Foreign Address State PID TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 11223
Listelenen satırda PID altında görüntülenen numarayı "process_id" alanına yazıp komutu çalıştırınız.
taskkill /F /PID process_id
Yukarda tanımlı komutta /F parametresi ile taskın kill edilmesini force etmekteyiz. /PID komutu ile de kill işleminin process id ile gerçekleştirmek istediğimizi belirtmekteyiz.
Örneğin, "sudo kill -9 1234" komutunu kullanarak 1234 kimlik numaralı bir işlemi sonlandırabilirsiniz.
Eğer Windows işletim sisteminde komut satırı üzerinden işlem yapmayı pek tercih etmiyorsanız aşağıda Görev Yöneticisi üzerinden de ilgili portun kill edilmesini sağlayabilirsiniz. Bunun için cihazınızda Görev Yöneticisini açmanız ve listelenen tasklarda size ait olanı bulup sağa tıklayıp Taskı Durdur seçeneğini seçmenizdir.
]]>JavaScript dilinde, tarih ve saat işlemleri için kullanılan Date nesnesi bulunur. Bu nesne, tarih ve saat bilgisini temsil eder ve bir dizi yöntem sunar, böylece tarihleri ve saatleri işleyebilirsiniz.
Date nesnesi oluştururken iki farklı yol vardır. İlk olarak, şu anki tarih ve saati almak için kullanabilirsiniz:
var now = new Date(); console.log(now);
Bu kod, Date nesnesini kullanarak geçerli zamanı ve tarihi alır ve ekrana yazdırır.
İkinci olarak, belirli bir tarih ve saat için Date nesnesi oluşturabilirsiniz:
var customDate = new Date(2022, 11, 13, 10, 30, 0); // 13 Aralık 2022, saat 10:30 console.log(customDate);
Date nesnesi, tarih ve saat bilgisini almak ve işlemek için birçok yöntem sunar. İşte bazı temel yöntemler:
Örnek olarak:
console.log(customDate.getFullYear()); // 2022 console.log(customDate.getMonth()); // 11 console.log(customDate.getDate()); // 13 console.log(customDate.getHours()); // 10 console.log(customDate.getMinutes()); // 30 console.log(customDate.getSeconds()); // 0
Date nesnesi ayrıca tarih işlemleri yapmanıza olanak tanır. İki tarih arasındaki farkı hesaplamak veya tarihleri karşılaştırmak gibi işlemler yapabilirsiniz.
Örnek olarak, iki tarih arasındaki farkı hesaplama:
var startDate = new Date(2023, 0, 1); var endDate = new Date(2023, 7, 1); var timeDifference = endDate - startDate; console.log(timeDifference / (1000 * 60 * 60 * 24)); // Gün cinsinden fark
Bu örnekte, iki tarih arasındaki gün farkını hesaplıyoruz.
Node.js kullanarak Date nesnesi, tarih ve saat işlemleri için güçlü bir araçtır. Bu makalede temel kullanımı ve temel yöntemleri öğrendiniz. Daha fazla bilgi ve örnekler için JavaScript belgelerine başvurabilirsiniz. Tarih ve saat işlemleri ile ilgili daha karmaşık senaryolar için bu temel bilgi size iyi bir başlangıç noktası sağlayacaktır.
]]>Zuckerberg, şirketin geleceğinin, kullanıcıları farklı bir ortam aracılığıyla birbirine bağlayan sanal gerçeklik ürünleri oluşturmaya odaklanacağını söyledi. Önümüzdeki on yıl içerisinde bir milyar insanın Metaverse olarak adlandırdıkları sanal dünyaya dahil olacağını dile getirdi.
Şirket, Metaverse platformunu kullanıcıların kendilerini temsil eden avatarlar oluşturabilecekleri üç boyutlu bir sanal alan olarak tanımlıyor. Zuckerberg, yeni sanal gerçeklik dünyasının kullanıcıların oturma odalarından çıkmadan video oyunları oynamasına, film izlemesine, konserlere katılmasına, meslektaşlarıyla işbirliği yapmasına ve arkadaşlarıyla bir araya gelmesine olanak sağlayacağını söyledi.
Zuckerberg, 2004 yılında üniversitenin yurt odasından başlattığı Facebook'u "ikonik bir sosyal medya şirketi" olarak adlandırmıştı, ancak bu adın artık şirketin vizyonuna "yeterli olmadığını" da sözlerine ekledi.
Şirket ayrıca 1 Aralık'tan itibaren FB olan hisse senedini MVRS olarak değiştiriyor.
Hatırlarsanız Facebook uzun süredir sahibi olduğu sosyal medya uygulamalarındaki kullanıcılara sağladığı koruma eksikliği nedeniyle eleştirilerle karşı karşıya. Bu ayın başlarında, eski Facebook çalışanı Frances Haugen, şirket yöneticilerinin platformun yıllardır yanlış bilgilerin yayılmasına yardımcı olduğunu bildiklerini ancak olumsuz etkilerle mücadele etmek için yeterli çabayı göstermediğini gösteren binlerce belgeyi sızdırdıktan sonra kamuoyuna açıklama yaptı. Zuckerberg Perşembe günü yaptığı açıklamada, "gizlilik" ve "güvenlik" kontrollerinin ilk günden itibaren Metaverse'e yerleştirilmesi gerektiğini söyledi.
]]>Yüksek trafiğe sahip olan şirketlerden kastımız Microsoft, IBM, Google, Adobe, Atlassian, T-Mobile, GitLab, DuckDuckGo, Salesforce, LinkedIn, Cisco, Facebook, Target, Twitter, Apple, Intel vb. firmalara ait sistemler ve sitelerdir. Aslında Nginx'in hikayesi Ekim 2014 tarihinde Igor Sysoev un cıktıgı ilk release dayanıyor. Igor, mevcut web sunucularında 10K ve üzeri paralel işlemlerde performans problemi ile karşılaşıldığını gözlemledi ve bunun çözümüne yönelik Nginx isimli sistemi hayata geçirdi. Tamamen açık kaynak olarak hazırlanan sistem şu anda dünyada en popüler web sunucuları listesinde ilk sıralarda.
Nginx, düşük bellek kullanımı ile birlikte paralel işlemlerin sorunsuz şekilde çalışmasına yönelik bir yapı üzerine kurulmuştur. Web sunucuya gelen tüm requestlerde yeni bir process açmak yerine tek process üzerinden tüm işlemlerin paralel şekilde yürütülmesini hedeflemiş ve bu kurguda çalışmaktadır. Nginx sunucularında, bir ana process birden çok çalışan processi kontrol edebilmektedir. Nginx üzerinden bulunan herhangi bir istek, diğer istekleri engellemeden çalışan processler tarafından eşzamanlı olarak yürütülebilir.
Nginx üzerinde kullanılan önemli özellikler şunlardır;
- IPv6
- Cacheleme ile reverse proxy
- Load balancing
- FastCGI destekli cacheleme sistemi
- WebSocketler
Apache, Nginx gibi tamamen açık kaynak kodlu popüler websunuculardan diğeridir. Hatta rakamlar karşılaştırıldığında Apache, %43,6 kullanım oranıyla Nginx'den daha fazla kullanılmaktadır. Nginx içinse oran %41.9 olarak tespit edilmiştir ancak her geçen yıl kullanım oranı Nginx yönünde artmaktadır.
Kullanım oranı olarak Apache önde gözüküyor olsa bile en fazla trafik olan sistemler karşılaştırıldığında Nginx in kullanım oranı daha fazladır. Yani popüler sistemlere ait sunuculara gelen trafiklerde Nginx tabanlı sunucular tercih edilmektedir. Netflix, NASA, Wordpress gibi popüler sistemlerde de Nginx tercih edilmektedir.
Websitelerinde hangi websunucunun çalıştığını tespit etmek amacıyla server isimli HTTP Header mesajını gözlemlemeniz yeterli olacaktır. Bu mesajı gözlemlemek için Google Chrome uygulamasında Developer Tools alanına tıklayıp Network sekmesini açınız. Sonrasında F5 tuşuna basıp sayfayı yenilediğinizde websitesine ait header mesajlarının network alanında listelendiğini gözlemleyebilirsiniz.
Yukarıdaki resimde yazilimdersi.info sitemizin çalıstığı websunucunun Apache olduğunu görebilirsiniz. Aynı şekilde facebook.com, google.com gibi farklı popüler sitelerinde sunucu bilgilerine bu yöntemle ulaşabilirsiniz. Ancak unutmamanız gereken konu bu bilgiler her zaman açık olarak paylaşılmamaktadır. Eğer sunuculardan sorumlu ekip, websitelerinde header bilgisi olarak sunucunun paylaşılmasını engellemek isterse, ilgili sunucu üzerinde bu bilgiyi saklayabilir.
]]>Daha önce sizlerle paylaştığımız "Android'de örnek login ve registration sayfası dizaynı" başlıklı makalemizde uygulama arayüzünün nasıl oluşturulduğunu sizlerle paylaşmıştık. Bu makalemizde arayüzü sadece design olarak degil, fonksiyonel hale getirmeye başlayacağız.
Mobil uygulama ile veri alışverişini sorunsuz şekilde gerçekleştirmek, gelen verilerin MySQL veritabanına kaydedilmesini sağlamak amacıyla Rest API kurgusunu hazırlamamız gerekecektir. API, bu tip verilerin karşılıklı aktığı sistemlerde mobil uygulama ile sunucu arasında ortak bir protokol olarak da isimlendirilebilir. Biz bu makalede PHP ve MySQL kullanarak bu işlemi gerçekleştireceğiz. Eğer siz Nodejs veya Ruby konusunda daha yetkinseniz bunları da kullanmanızda herhangi bir mahsur yoktur. Hazırlayacağımız API yapacağı işlemler şu şekildedir;
- GET/POST metodları üzerinden API çağrılarının alınması
- Veritabanına yeni kullanıcı kaydının oluşturulması
- Veritabanında kayıtlı olan kullanıcının bilgilerinin çekilmesi
- API cevaplarının JSON formatta iletilmesi
Öncelikle server tarafının çalışacağı webserverin belirlenmesi ve kurulması gerekmektedir. Projemizde pratik ve hızlı bir çözüm sunacağını düşündüğümüz WampServer'i tercih edeceğiz. Wampserver kurulumu ile birlikte Apache, PHP ve MySQL kurulumlarını tek seferde gerçekleştirmiş oluyoruz. Wampserver kurulumu için www.wampserver.com/en/ linkine tıklayınız. Programı indirip kurulumu gerçekleştirdikten sonra Start ⇒ All Programs ⇒ WampServer ⇒ StartWampServer seçeneğinden Wampserveri başlatabilirsiniz. Eğer MAC bilgisayarınız varsa WAMP yerine MAMP Server kurulumunu gerçekleştirebilirsiniz. MAMP Servere erişmek için https://www.mamp.info/en/downloads/ linkine tıklayınız.
Artık projenin sunucu tarafını http://localhost üzerinden test edebilirsiniz. Veritabanına erişim içinse http://localhost/phpmyadmin linkinden yararlanabilirsiniz.
WAMPServer kurulumu sonrasında artık MySQL veritabanına erişimi kolaylıkla gerçekleştirebiliriz. Burada http://localhost/phpmyadmin linki üzerinden veritabanına erişim sağlayabilirsiniz. Öncelikle ornek_proje adında bir veritabanı oluşturalım. Sonrasında da bu veritabanına içerisinde kullanicilar adında bir tablo oluşturalım.
CREATE DATABASE ornek_proje USE ornek_proje CREATE TABLE kullanicilar( id int(11) primary key auto_increment, unique_id varchar(23) not null unique, name varchar(50) not null, email varchar(100) not null unique, encrypted_password varchar(80) not null, salt varchar(10) not null, created_at datetime, updated_at datetime null );
MYSQL üzerinde veritabanı ve tabloları oluşturduktan sonra PHP dili kullanılarak API kısmının yazılmasında sıra. Burada öncelikle WAMPServeri kurduğunuz dizine gidip www dizini altında ornek_proje baslıgında bir dizin oluşturun. Bu dizin içerisine API yi hazırlarken kullanacağınız PHP kodlamalarını yerleştireceğiz. Projeye ait klasör yapısı aşağıdaki şekilde olacaktır.
Projede kullanılan PHP sınıfları;
config.php: Veritabanına bağlantısında kullanılacak config bilgilerin setlendiği sınıf.
db_connect.php: Veritabanı bağlantısının sağlandığı sınıf.
db_functions.php: Veritabanı üzerinde gerçekleştirilecek olan işlemlerde kullanılan sınıf.
login.php: Android uygulamadan login olmaya çalışılırken kullanılan sınıf.
register.php: Android uygulamadan register olmaya çalışırken kullanılan sınıf.
Projede config.php dosyasının içerisine aşağıdaki kodlamayı yapıştıralım.
<?php define("DB_HOST", "localhost"); define("DB_USER", "root"); define("DB_PASSWORD", "rootsifre"); define("DB_DATABASE", "ornek_proje"); ?>
Bu dosyada DB_USER ve DB_PASSWORD alanlarının karşısına veritabanını oluştururken kullandığınız kullanıcı adı ve şifre bilgilerini yerleştiriniz.
Sonrasında db_connect.php dosyasının içerisine aşağıdaki kodlamayı yapıştıralım.
<?php class db_connect { private $conn; public function connect() { require_once 'include/config.php'; $this-?>conn = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE); return $this-?>conn; } } ?>
Şimdi veritabanı işlemlerini gerçekleştireğimiz db_functions.php dosyasını oluşturup içerisine aşağıdaki kodlamaları yapıştıralım. Bu sınıf içerisinde tanımlanan fonksiyonlar; yeni kullanıcı oluşturulması veya mevcut olan kullanıcıların veritabanından getirilmesinde kullanılacaktır. Sınıf içerisinde tanımlanan uniqid('', true) metodu ile her kullanıcıya uniq bir id tanımlanması hedeflenmektedir. base64_encode metodu ile de kullanıcı şifresinin hashlenmesi sağlanmaktadır. Burada güvenliği üst seviyede tutmak adına salt verisi ve hashlenmiş şifrelerin veritabanında tutulması sağlanmaktadır.
<?php class db_functions { private $conn; function __construct() { require_once 'db_connect.php'; $db = new db_connect(); $this->conn = $db->connect(); } function __destruct() { } public function storeUser($name, $email, $password) { $uuid = uniqid('', true); $hash = $this->hashSSHA($password); $encrypted_password = $hash["encrypted"]; $salt = $hash["salt"]; $stmt = $this->conn->prepare("INSERT INTO kullanicilar(unique_id, name, email, encrypted_password, salt, created_at) VALUES(?, ?, ?, ?, ?, NOW())"); $stmt->bind_param("sssss", $uuid, $name, $email, $encrypted_password, $salt); $result = $stmt->execute(); $stmt->close(); if ($result) { $stmt = $this->conn->prepare("SELECT * FROM kullanicilar WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $user = $stmt->get_result()->fetch_assoc(); $stmt->close(); return $user; } else { return false; } } public function getUserByEmailAndPassword($email, $password) { $stmt = $this->conn->prepare("SELECT * FROM kullanicilar WHERE email = ?"); $stmt->bind_param("s", $email); if ($stmt->execute()) { $user = $stmt->get_result()->fetch_assoc(); $stmt->close(); $salt = $user['salt']; $encrypted_password = $user['encrypted_password']; $hash = $this->checkhashSSHA($salt, $password); if ($encrypted_password == $hash) { return $user; } } else { return NULL; } } public function isUserExisted($email) { $stmt = $this->conn->prepare("SELECT email from kullanicilar WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $stmt->store_result(); if ($stmt->num_rows > 0) { $stmt->close(); return true; } else { $stmt->close(); return false; } } public function hashSSHA($password) { $salt = sha1(rand()); $salt = substr($salt, 0, 10); $encrypted = base64_encode(sha1($password . $salt, true) . $salt); $hash = array("salt" => $salt, "encrypted" => $encrypted); return $hash; } public function checkhashSSHA($salt, $password) { $hash = base64_encode(sha1($password . $salt, true) . $salt); return $hash; } } ?>
Yukarıda tanımladığımız Php sınıfı ile birlikte artık ihtiyacımız olan tüm yapılar hazır durumdadır. Şimdi birlikte yeni kullanıcı kaydı oluşturacak sınıfı yazalım. Kullanıcı kaydında name, email ve password gibi alanları kullanarak sistemimizi hazırlayalım. Bu veriler Android uygulamamız üzerinden POST metodu ile iletilecektir.
Şimdi Php projemizin olduğu dizinde register.php isminde dosya oluşturup aşağıdaki kodlamayı içerisine yapıştıralım.
<?php require_once 'include/db_functions.php'; $db = new db_functions(); $response = array("error" => FALSE); if (isset($_POST['name']) && isset($_POST['email']) && isset($_POST['password'])) { $name = $_POST['name']; $email = $_POST['email']; $password = $_POST['password']; // kullanıcı sistemde kayıtlı bir email ile hesap oluşturuyormu? if ($db->isUserExisted($email)) { // kullanıcı sistemde kayıtlı ise $response["error"] = TRUE; $response["error_msg"] = $email. " maili ile ilişkili bir hesap sistemde bulunmaktadır"; echo json_encode($response); } else { // yeni kullanıcı oluşturalım $user = $db->storeUser($name, $email, $password); if ($user) { // kullanıcı başarılı şekilde kayıt edildi $response["error"] = FALSE; $response["uid"] = $user["unique_id"]; $response["user"]["name"] = $user["name"]; $response["user"]["email"] = $user["email"]; $response["user"]["created_at"] = $user["created_at"]; $response["user"]["updated_at"] = $user["updated_at"]; echo json_encode($response); } else { // kullanıcı sisteme kayıt edilemedi $response["error"] = TRUE; $response["error_msg"] = "Hesap oluşturulurken bilinmedik bir sorun ile karşılaşıldı!"; echo json_encode($response); } } } else { $response["error"] = TRUE; $response["error_msg"] = "Lütfen zorunlu parametreleri(name, email ve password) eksiksiz girin!"; echo json_encode($response); } ?>
Başarılı Kullanıcı Kaydında API den dönecek cevap şu şekilde olacaktır;
{ "error": false, "uid": "44fa7220a2c187.2191519", "user": { "name": "Yazılım Dersi", "email": "[email protected]", "created_at": "2021-03-28 15:26:26", "updated_at": null } }
Kullanıcı Kaydında sorun yaşandığında API den dönecek cevap şu şekilde olacaktır;
{ "error": 1, "error_msg": "Hesap oluşturulurken bilinmedik bir sorun ile karşılaşıldı!" }
Kayıtlı kullanıcı kaydında API den dönecek cevap şu şekilde olacaktır;
{ "success": 0, "error": 2, "error_msg": "[email protected] maili ile ilişkili bir hesap sistemde bulunmaktadır" }
Register işleminin ardından sistemde kayıtlı olan kullanıcıların kontrol edilmesi için Login yani Giriş yapısının kurgulanması gerekecektir. Burada genel olarak kullanılan email ve password ile kullanıcı kontrolünün gerçekleştirilmesidir. İletilecek parametreler POST metodu ile Android uygulama üzerinden iletilecektir. Yapacağımız kontrolde eğer email ve password bilgileri uyuşan herhangi bir kayıt olursa bununla alakalı başarılı sistem cevabını API üzerinden sunacağız. Eğer kayıtlı herhangi bir kullanıcı ile eşleşmiyorsa, o zamanda fail olan mesajımızı API üzerinden ileteceğiz.
Şimdi Php projemizin olduğu dizinde login.php isminde dosya oluşturup aşağıdaki kodlamayı içerisine yapıştıralım.
<?php require_once 'include/db_functions.php'; $db = new db_functions(); $response = array("error" => FALSE); if (isset($_POST['email']) && isset($_POST['password'])) { // parametreler $email = $_POST['email']; $password = $_POST['password']; // email ve password bilgilerinin kontrol edilmesi $user = $db->getUserByEmailAndPassword($email, $password); if ($user != false) { // kullanıcı bulundu $response["error"] = FALSE; $response["uid"] = $user["unique_id"]; $response["user"]["name"] = $user["name"]; $response["user"]["email"] = $user["email"]; $response["user"]["created_at"] = $user["created_at"]; $response["user"]["updated_at"] = $user["updated_at"]; echo json_encode($response); } else { // bu bilgilerle uyumlu kullanıcı bulunamadı $response["error"] = TRUE; $response["error_msg"] = "Kullanıcı bilgileri yanlıştır. Lütfen daha sonra tekrar deneyin!"; echo json_encode($response); } } else { // zorunlu parametreleri iletiniz $response["error"] = TRUE; $response["error_msg"] = "Lütfen zorunlu parametreleri(email ve password) eksiksiz girin!"; echo json_encode($response); } ?>
Başarılı Kullanıcı Giriş Kontrolünde API den dönecek cevap şu şekilde olacaktır;
{ "error": false, "uid": "44fa7220a2c187.2191519", "user": { "name": "Yazılım Dersi", "email": "[email protected]", "created_at": "2021-03-28 15:26:26", "updated_at": null } }
Başarısız kullanıcı kontrolünde API den dönecek cevap şu şekilde olacaktır;
{ "tag": "login", "success": 0, "error": 1, "error_msg": "Kullanıcı bilgileri yanlıştır. Lütfen daha sonra tekrar deneyin!" }
Şu ana kadar yapılan çalışma ile API kısmındaki düzenlemeler tamamlandı. Şimdi Android uygulamasını yazmaya başlayalım.
Yapacağımız örnek projede json formatta response dönen API çağrısından ( Yukarıda adım adım paylaşılan API) veriyi parse edip login ve register kavramlarını uygulayacağız.
1. File => New Project seçeneğine tıklayalım. Sonrasında açılan ekranda Empty Activity seçeneğini seçip Next butonuna tıklayalım.dependencies { ......... // volley kütüphanesini ekleyelim implementation 'com.mcxiaoke.volley:library-aar:1.0.0' // appcompat ve material kütüphanelerini ekleyelim implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.4.0-alpha01' }5. Projemizde internet üzerinden API çağrısı yapılacağı için AndroidManifest.xml dosyasında INTERNET iznini almamız gerekmektedir kullanıcıdan. Ayrıca hazırlanan activitylerin manifest dosyası içerisinde aşağıdaki şekilde tanımlanması gerekecektir.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="info.yazilimdersi.sampleapp"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name="info.yazilimdersi.sampleapp.core.AppController" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".LoginActivity" android:label="@string/app_name" android:launchMode="singleTop" android:windowSoftInputMode="adjustPan"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".RegisterActivity" android:label="@string/app_name" android:launchMode="singleTop" android:windowSoftInputMode="adjustPan" /> <activity android:name=".MainActivity" android:label="@string/app_name" android:launchMode="singleTop" /> </application> </manifest>6. Projede tanımlanan labelleri strings.xml dosyası içerisinde tanımlayalım.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Android Uygulama</string> <string name="hint_email">Email</string> <string name="hint_password">Şifre</string> <string name="hint_name">İsim</string> <string name="btn_login">GİRİŞ</string> <string name="btn_register">HESAP OLUŞTUR</string> <string name="btn_link_to_register">Üye değilmisiniz? Hesap oluşturun.</string> <string name="btn_link_to_login">Hesabınız bulunmaktamı? Giriş Yapın.</string> <string name="welcome">Merhaba</string> <string name="btn_logout">ÇIKIŞ</string> <string name="name">İsim</string> </resources>7. Projede tanımlanan renkleri colors.xml dosyası içerisinde tanımlayalım.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="bg_login">#26ae90</color> <color name="bg_register">#2e3237</color> <color name="bg_main">#428bca</color> <color name="white">#ffffff</color> <color name="input_login">#222222</color> <color name="input_login_hint">#999999</color> <color name="input_register">#888888</color> <color name="input_register_bg">#3b4148</color> <color name="input_register_hint">#5e6266</color> <color name="btn_login">#26ae90</color> <color name="btn_login_bg">#eceef1</color> <color name="lbl_name">#333333</color> <color name="btn_logut_bg">#ff6861</color> </resources>8. Projede app=>core dizini altında AppConfig.java dosyası oluşturup aşağıdaki kodlamayı içerisinde tanımlayalım.
public class AppConfig { public static String URL_LOGIN = "http://192.168.1.3/api/login.php"; public static String URL_REGISTER = "http://192.168.1.3/api/register.php"; }9. Projede app=>core dizini altında AppController.java dosyası oluşturup aşağıdaki kodlamayı içerisinde tanımlayalım. Bu dosya Application sınıfını extend edip uygulamada tanımlanması gereken genel ayarları belirlemede kullanılacaktır.
import android.app.Application; import android.text.TextUtils; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; public class AppController extends Application { public static final String TAG = AppController.class.getSimpleName(); private RequestQueue mRequestQueue; private static AppController mInstance; @Override public void onCreate() { super.onCreate(); mInstance = this; } public static synchronized AppController getInstance() { return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req, String tag) { req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } public <T> void addToRequestQueue(Request<T> req) { req.setTag(TAG); getRequestQueue().add(req); } public void cancelPendingRequests(Object tag) { if (mRequestQueue != null) { mRequestQueue.cancelAll(tag); } } }10. Projemizde login olan kullanıcının olup olmadığını belirlemek adına hazırlanan SessionManager.java sınıfını aşağıdaki şekilde dolduralım. Hazırlanan sınıf sayesinde daha önceden herhangi bir kullanıcının login olup olmadığı SharedPreferences üzerinden kontrol edilip hazırladığımız fonksiyonlarla check edilecektir.
import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.util.Log; public class SessionManager { private static String TAG = SessionManager.class.getSimpleName(); SharedPreferences pref; Editor editor; Context _context; int PRIVATE_MODE = 0; private static final String PREF_NAME = "AndroidApp"; private static final String KEY_IS_LOGGEDIN = "isLoggedIn"; public SessionManager(Context context) { this._context = context; pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE); editor = pref.edit(); } public void setLogin(boolean isLoggedIn) { editor.putBoolean(KEY_IS_LOGGEDIN, isLoggedIn); editor.commit(); Log.d(TAG, "Kullanıcı sisteme giriş yaptı!"); } public boolean isLoggedIn(){ return pref.getBoolean(KEY_IS_LOGGEDIN, false); } }11. Projemizde login olan kullanıcı bilgilerinin telefonda tutulması adına hazırlanan SQLiteHandler.java sınıfını aşağıdaki şekilde hazırlayalım. Hazırlanan sınıf sayesinde login olan kullanıcının bilgilerinin SQLiteOpenHelper üzerinden kayıt altına alınması sağlanacaktır.
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; import java.util.HashMap; public class SQLiteHandler extends SQLiteOpenHelper { private static final String TAG = SQLiteHandler.class.getSimpleName(); private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "androidapp"; private static final String TABLE_USER = "user"; private static final String KEY_ID = "id"; private static final String KEY_NAME = "name"; private static final String KEY_EMAIL = "email"; private static final String KEY_UID = "uid"; private static final String KEY_CREATED_AT = "created_at"; public SQLiteHandler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String CREATE_LOGIN_TABLE = "CREATE TABLE " + TABLE_USER + "(" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT," + KEY_EMAIL + " TEXT UNIQUE," + KEY_UID + " TEXT," + KEY_CREATED_AT + " TEXT" + ")"; db.execSQL(CREATE_LOGIN_TABLE); Log.d(TAG, "Veritabanı oluşturuldu"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_USER); onCreate(db); } /** * login olan kullanıcı bilgisinin kayıt altına alınması * */ public void addUser(String name, String email, String uid, String created_at) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(KEY_NAME, name); // isim values.put(KEY_EMAIL, email); // email values.put(KEY_UID, uid); // email values.put(KEY_CREATED_AT, created_at); // oluşturulduğu tarih long id = db.insert(TABLE_USER, null, values); db.close(); Log.d(TAG, "New user inserted into sqlite: " + id); } /** * veritabanından kullanıcı bilgilerinin getirilmesi * */ public HashMap<String, String> getUserDetails() { HashMap<String, String> user = new HashMap<String, String>(); String selectQuery = "SELECT * FROM " + TABLE_USER; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); cursor.moveToFirst(); if (cursor.getCount() > 0) { user.put("name", cursor.getString(1)); user.put("email", cursor.getString(2)); user.put("uid", cursor.getString(3)); user.put("created_at", cursor.getString(4)); } cursor.close(); db.close(); return user; } /** * veritabanında kayıtlı kullanıcıların silinmesi * */ public void deleteUsers() { SQLiteDatabase db = this.getWritableDatabase(); db.delete(TABLE_USER, null, null); db.close(); } }
Projemizde kullanıcının ilk karşılaşacağı ekran olan LoginActivity ekranının hazırlanmasına geldi sıra. AndroidManifest.xml dosyasında default olarak bu Activity nin açılacağını belirlemiştik. res => layout dizini altında activity_login.xml dosyası oluşturup aşağıdaki kodu yapıştıralım.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white" android:gravity="center" android:orientation="vertical" android:padding="10dp" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp" > <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:src="@drawable/logo" /> <EditText android:id="@+id/email" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@color/bg_login" android:hint="@string/hint_email" android:inputType="textEmailAddress" android:padding="10dp" android:singleLine="true" android:textColor="@color/white" android:textColorHint="@color/white" /> <EditText android:id="@+id/password" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@color/bg_login" android:hint="@string/hint_password" android:inputType="textPassword" android:padding="10dp" android:singleLine="true" android:textColor="@color/white" android:textColorHint="@color/white" /> <Button android:id="@+id/btnLogin" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dip" android:background="@color/btn_login_bg" android:text="@string/btn_login" android:textColor="@color/btn_login" /> <Button android:id="@+id/btnLinkToRegisterScreen" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="40dip" android:background="@null" android:text="@string/btn_link_to_register" android:textAllCaps="false" android:textColor="@color/bg_register" android:textSize="15dp" /> </LinearLayout> </LinearLayout>
Bu arayüz ile ilişkili LoginActivity.java sınıfının içeriğini aşağıdaki şekilde belirleyelim. checkLogin() metodu ile kullanıcının bilgilerini API üzerinden talep edelim.
import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.android.volley.Request.Method; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; import info.yazilimdersi.sampleapp.core.AppConfig; import info.yazilimdersi.sampleapp.core.AppController; import info.yazilimdersi.sampleapp.helper.SQLiteHandler; import info.yazilimdersi.sampleapp.helper.SessionManager; public class LoginActivity extends Activity { private static final String TAG = RegisterActivity.class.getSimpleName(); private Button btnLogin; private Button btnLinkToRegister; private EditText inputEmail; private EditText inputPassword; private ProgressDialog pDialog; private SessionManager session; private SQLiteHandler db; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); inputEmail = (EditText) findViewById(R.id.email); inputPassword = (EditText) findViewById(R.id.password); btnLogin = (Button) findViewById(R.id.btnLogin); btnLinkToRegister = (Button) findViewById(R.id.btnLinkToRegisterScreen); pDialog = new ProgressDialog(this); pDialog.setCancelable(false); db = new SQLiteHandler(getApplicationContext()); session = new SessionManager(getApplicationContext()); // kullanıcının daha önceden giriş yapıp yapmadığını sorgula if (session.isLoggedIn()) { // kullanıcı daha önceden giriş yapmıştı. MainActivity sınıfına yönlendir Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } // giriş butonu btnLogin.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { String email = inputEmail.getText().toString().trim(); String password = inputPassword.getText().toString().trim(); // herhangi eksik bilgi varmı kontrolü if (!email.isEmpty() && !password.isEmpty()) { // kullanıcı girisi checkLogin(email, password); } else { // hata mesajı Toast.makeText(getApplicationContext(), "Lütfen tüm bilgileri eksiksiz giriniz!", Toast.LENGTH_LONG) .show(); } } }); btnLinkToRegister.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent(getApplicationContext(), RegisterActivity.class); startActivity(i); finish(); } }); } /** * kullanıcı kontrolü * */ private void checkLogin(final String email, final String password) { String tag_string_req = "req_login"; pDialog.setMessage("Giriş yapılıyor..."); showDialog(); StringRequest strReq = new StringRequest(Method.POST, AppConfig.URL_LOGIN, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d(TAG, "Login Response: " + response.toString()); hideDialog(); try { JSONObject jObj = new JSONObject(response); boolean error = jObj.getBoolean("error"); // hata kodlarının kontrol edilmesi if (!error) { // kullanıcı basarılı sekilde giris yaptı session.setLogin(true); String uid = jObj.getString("uid"); JSONObject user = jObj.getJSONObject("user"); String name = user.getString("name"); String email = user.getString("email"); String created_at = user .getString("created_at"); // kullanıcı kaydı oluşturuldu db.addUser(name, email, uid, created_at); // MainActivity çağrıldı Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } else { String errorMsg = jObj.getString("error_msg"); Toast.makeText(getApplicationContext(), errorMsg, Toast.LENGTH_LONG).show(); } } catch (JSONException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "Json error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "Login Error: " + error.getMessage()); Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show(); hideDialog(); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put("email", email); params.put("password", password); return params; } }; AppController.getInstance().addToRequestQueue(strReq, tag_string_req); } private void showDialog() { if (!pDialog.isShowing()) pDialog.show(); } private void hideDialog() { if (pDialog.isShowing()) pDialog.dismiss(); } }
Yapılan düzenleme sonrası login ekranına ait ekran görüntüsü aşağıdaki şekilde olacaktır.
Projemizde yeni kullanıcı kaydının oluşturulmasında kullanılacak olan RegisterActivity ekranının hazırlanmasına geldi sıra. Kullanıcıya ait name, email ve password bilgilerinin bu arayüz üzerinden girilmesi gerekmektedir.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white" android:gravity="center" android:orientation="vertical" android:padding="10dp" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp" > <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:src="@drawable/logo" /> <EditText android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@color/input_register_bg" android:hint="@string/hint_name" android:padding="10dp" android:singleLine="true" android:inputType="textCapWords" android:textColor="@color/white" android:textColorHint="@color/white" /> <EditText android:id="@+id/email" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@color/input_register_bg" android:hint="@string/hint_email" android:inputType="textEmailAddress" android:padding="10dp" android:singleLine="true" android:textColor="@color/white" android:textColorHint="@color/white" /> <EditText android:id="@+id/password" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@color/input_register_bg" android:hint="@string/hint_password" android:inputType="textPassword" android:padding="10dp" android:singleLine="true" android:textColor="@color/white" android:textColorHint="@color/white" /> <Button android:id="@+id/btnRegister" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="20dip" android:background="#ea4c88" android:text="@string/btn_register" android:textColor="@color/white" /> <Button android:id="@+id/btnLinkToLoginScreen" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="40dip" android:background="@null" android:text="@string/btn_link_to_login" android:textAllCaps="false" android:textColor="@color/bg_register" android:textSize="15dp" /> </LinearLayout> </LinearLayout>
Bu arayüz ile ilişkili RegisterActivity.java sınıfının içeriğini aşağıdaki şekilde belirleyelim. registerUser() metodu ile yeni kullanıcı kaydını gerçekleştirelim.
import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.android.volley.Request.Method; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; import info.yazilimdersi.sampleapp.R; import info.yazilimdersi.sampleapp.core.AppConfig; import info.yazilimdersi.sampleapp.core.AppController; import info.yazilimdersi.sampleapp.helper.SQLiteHandler; import info.yazilimdersi.sampleapp.helper.SessionManager; public class RegisterActivity extends Activity { private static final String TAG = RegisterActivity.class.getSimpleName(); private Button btnRegister; private Button btnLinkToLogin; private EditText inputFullName; private EditText inputEmail; private EditText inputPassword; private ProgressDialog pDialog; private SessionManager session; private SQLiteHandler db; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); inputFullName = (EditText) findViewById(R.id.name); inputEmail = (EditText) findViewById(R.id.email); inputPassword = (EditText) findViewById(R.id.password); btnRegister = (Button) findViewById(R.id.btnRegister); btnLinkToLogin = (Button) findViewById(R.id.btnLinkToLoginScreen); pDialog = new ProgressDialog(this); pDialog.setCancelable(false); session = new SessionManager(getApplicationContext()); db = new SQLiteHandler(getApplicationContext()); // kullanıcının daha önceden giriş yapıp yapmadığını sorgula if (session.isLoggedIn()) { // kullanıcı daha önceden giriş yapmıştı. MainActivity sınıfına yönlendir Intent intent = new Intent(RegisterActivity.this, MainActivity.class); startActivity(intent); finish(); } // hesap oluştur butonu btnRegister.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { String name = inputFullName.getText().toString().trim(); String email = inputEmail.getText().toString().trim(); String password = inputPassword.getText().toString().trim(); if (!name.isEmpty() && !email.isEmpty() && !password.isEmpty()) { registerUser(name, email, password); } else { Toast.makeText(getApplicationContext(), "Lütfen eksiksiz olarak tüm bilgileri giriniz!", Toast.LENGTH_LONG) .show(); } } }); btnLinkToLogin.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent(getApplicationContext(), LoginActivity.class); startActivity(i); finish(); } }); } private void registerUser(final String name, final String email, final String password) { String tag_string_req = "req_register"; pDialog.setMessage("Hesap Oluşturuluyor..."); showDialog(); StringRequest strReq = new StringRequest(Method.POST, AppConfig.URL_REGISTER, new Response.Listener<String>() { @Override public void onResponse(String response) { hideDialog(); try { JSONObject jObj = new JSONObject(response); boolean error = jObj.getBoolean("error"); if (!error) { String uid = jObj.getString("uid"); JSONObject user = jObj.getJSONObject("user"); String name = user.getString("name"); String email = user.getString("email"); String created_at = user .getString("created_at"); // users tablosuna icerik ekleyin db.addUser(name, email, uid, created_at); Toast.makeText(getApplicationContext(), "Kullanıcı başarılı şekilde giriş yaptı. Şimdi giriş yapın!", Toast.LENGTH_LONG).show(); // login ekranına yönlendir Intent intent = new Intent( RegisterActivity.this, LoginActivity.class); startActivity(intent); finish(); } else { // hata mesajı String errorMsg = jObj.getString("error_msg"); Toast.makeText(getApplicationContext(), errorMsg, Toast.LENGTH_LONG).show(); } } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "Registration Error: " + error.getMessage()); Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show(); hideDialog(); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put("name", name); params.put("email", email); params.put("password", password); return params; } }; AppController.getInstance().addToRequestQueue(strReq, tag_string_req); } private void showDialog() { if (!pDialog.isShowing()) pDialog.show(); } private void hideDialog() { if (pDialog.isShowing()) pDialog.dismiss(); } }
Yapılan düzenlemeler sonrası register ekranına ait ekran görüntüsü aşağıdaki şekilde olacaktır.
Uygulamaya giriş yapan kullanıcının karşılaşacağı MainActivity ekranının hazırlanmasını gerçekleştirelim. Bu arayüzde en basitinden giriş yapılmış olan kullanıcıya ait name, email bilgileri görüntülenecektir. Ayrıca kullanıcının logout olmasına imkan sunan bir butonda bu ekranda görüntülenecektir.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/welcome" android:textSize="20dp" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:textColor="@color/lbl_name" android:textSize="24dp" /> <TextView android:id="@+id/email" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="13dp" /> <Button android:id="@+id/btnLogout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="40dip" android:background="@color/btn_logut_bg" android:text="@string/btn_logout" android:textAllCaps="false" android:textColor="@color/white" android:textSize="15dp" /> </LinearLayout> </RelativeLayout>
Bu arayüz ile ilişkili RegisterActivity.java sınıfının içeriğini aşağıdaki şekilde belirleyelim. registerUser() metodu ile yeni kullanıcı kaydını gerçekleştirelim.
import info.yazilimdersi.sampleapp.helper.SQLiteHandler; import info.yazilimdersi.sampleapp.helper.SessionManager; import java.util.HashMap; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private TextView txtName; private TextView txtEmail; private Button btnLogout; private SQLiteHandler db; private SessionManager session; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtName = (TextView) findViewById(R.id.name); txtEmail = (TextView) findViewById(R.id.email); btnLogout = (Button) findViewById(R.id.btnLogout); db = new SQLiteHandler(getApplicationContext()); session = new SessionManager(getApplicationContext()); if (!session.isLoggedIn()) { logoutUser(); } // Kullanıcı bilgilerinin veritabanından getirilmesi HashMap<String, String> user = db.getUserDetails(); String name = user.get("name"); String email = user.get("email"); // Kullanıcı bilgilerinin ekranda görüntülenmesi txtName.setText(name); txtEmail.setText(email); // Çıkış butonu btnLogout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { logoutUser(); } }); } private void logoutUser() { session.setLogin(false); db.deleteUsers(); // login ekranının görüntülenmesi Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); finish(); } }
Yapılan düzenlemeler sonrası ana ekrana ait ekran görüntüsü aşağıdaki şekilde olacaktır.
Hem mobil uygulamaya ait kodlama hem de API ye ait kodlamaları tamamladık. Uygulamanın çalışırlığını test edebilmemiz adına aşağıdaki adımları uygulamanız gerekmektedir;
]]>
- AppConfig.java dosyasında tanımlanan URL_REGISTER ve URL_LOGIN linklerinin cihazınıza ait IP adresi ile değiştirilmesi gerekmektedir. Bunu öğrenmek için bilgisayarınızda komut istemcisini açıp ipconfig komutunu girdiğinizde gelen ekrandaki IPV4 Adres bilgisini kullanmanız gerekecektir.
- Mobil uygulamayı yüklediğiniz cihazla API nın olduğu bilgisayar aynı network üzerinde olmalıdır.
- config.php dosyasında username, password ve database alanına veritabanına erişimde kullanılan bilgiler girilmelidir.
Çoğu zaman modemlerin arayüzüne erişimde kullanıcı adı ve şifre bilgilerini ya unutuyoruz yada bilmiyoruz. Aşağıdaki listede yaygın olarak kullanılan modemlerin kullanıcı adı ve şifrelerini sizlerle paylaşıyoruz.
Zyxel modeminin default url adresi 192.168.1.1 ve kullanıcı adı "admin" dir. Eğer modemi Türk Telekom kampanyası ile aldıysanız şifre ttnet veya turktelekom, eğer Göknet firmasından aldıysanız şifre kısmına goknet yazarak modem arayüzüne giriş yapabilirsiniz. Eğer modemi farklı bir firmadan aldıysanız default şifre 1234 veya admin olabilir.
Tp-Link modeminin default url adresi 192.168.1.1 ve kullanıcı adı "admin" dir. Eğer modemi Türk Telekom kampanyası ile aldıysanız şifre kısmına ttnet veya turktelekom yazarak modem arayüzüne giriş yapabilirsiniz. Eğer modemi farklı bir firmadan aldıysanız default şifre 1234 veya admin olabilir.
AirTies modeminin default url adresi 192.168.2.1 ve kullanıcı adı "admin" dir. Eğer modemi Türk Telekom kampanyası ile aldıysanız şifre kısmına ttnet veya turktelekom yazarak modem arayüzüne giriş yapabilirsiniz. Eğer modemi farklı bir firmadan aldıysanız şifre alanı boş bırakılmalıdır.
Asus modeminin default url adresi 192.168.1.1 veya 192.168.1.254 ve kullanıcı adı "admin" dir. Default şifre olarak ise admini kullanabilirsiniz.
Pikatel ComboMax modeminin default url adresi 192.168.1.1 ve kullanıcı adı "admin" dir. Eğer modemi Türk Telekom kampanyası ile aldıysanız şifre kısmına ttnet veya turktelekom yazarak modem arayüzüne giriş yapabilirsiniz. Eğer modemi farklı bir firmadan aldıysanız default şifre password olabilir.
Şu ana kadar anlattığımız modemler Türkiye'de yaygın olarak kullanılan markalardır. Bu markaların dışında olan modemlerin listesi ve bilgileri şu şekildedir;
Modem Markası | URL Adresi | Kullanıcı | Şifre |
US Robotics | 10.0.0.2 | admin | admin |
Zoom X serisi | 10.0.0.2 | admin | zoomadsl |
Actiontec | 192.168.0.1 | admin | boş bırakınız |
Actiontec Verizon | 192.168.1.1 | admin | boş bırakınız |
Airties | 192.168.2.1 | admin | ttnet |
Airties RT206v2 (TTNET) | 192.168.2.1 | admin | ttnet |
Airties RT210 (TTNET) | 192.168.2.1 | boş bırakınız | boş bırakınız |
Airties RT210 (TTNET) | 192.168.2.1 | admin | ttnet |
Allied Telesyn | 192.168.1.1:8080 | manager | friend |
Apache | 192.168.1.1 | root veya setup | root |
Artes | 192.168.1.1 | admin | adslroot |
Aztech | 10.0.0.2 | admin | admin |
Bec | 192.168.1.254 | admin | admin |
Billion | 192.168.1.254 | admin | admin |
Billion Bipac | 192.168.1.254 | admin | password |
Bross | 192.168.1.1 | admin | 1234 |
C-Com | 192.168.1.1 | boş bırakınız | boş bırakınız |
Cnet | 10.0.0.2 | admin | epicrouter |
Corecess 3112 usb | 10.0.0.3 | admin | corecess3112 |
Corecess 3113 eth | 10.0.0.2 | admin | corecess3113 |
Creative | 192.168.1.1 | admin | admin |
Dibeg 108 | 192.168.1.1 | dare | boş bırakınız |
D-Link | 192.168.1.1 | admin | admin |
Datron ETHERNET | 192.168.1.1 | admin | admin |
Datron USB | 192.168.1.2 | admin | admin |
Dost GVC | 192.168.1.254 | admin | dostdost |
DryTek | 192.168.1.1 | admin | boş bırakınız |
Dynalink | 192.168.1.1 | admin | admin |
Edimax | 192.168.2.1 | admin | 1234 |
E-Con | 192.168.1.1 | admin | admin |
Eicon Diva | 10.0.0.2 | boş bırakınız | boş bırakınız |
Everest SG-1400 | 192.168.1.1 | admin | admin |
Fishnet AR-1101 (DOPING) | 192.168.1.1 | admin | 1234 |
Flynet | 192.168.1.1 | admin | admin |
Geek | 10.0.0.2 | admin | epicrouter veya geekadsl |
Gezz | 10.0.0.2 | admin | epicrouter |
Hayes | 10.0.0.2 | admin | hayesadsl |
Home Station DC 213 | 10.0.0.1 | admin | admin |
Home Station DC 214 | 192.168.1.254 | admin | password |
Hicomm | 10.0.0.2 | admin | epicrouter |
Huawei | 192.168.1.1 | admin | ttnet |
Inca | 192.168.1.1 veya 10.0.0.2 | admin | epicrouter |
Karel | 10.0.0.2 | admin | adslroot |
Ladox | 192.168.1.1 | admin | ladox |
Loopcom | 10.0.0.2 | admin | epicrouter |
Link SYS | 192.168.1.1 | admin | admin |
Mercury ADSL | 10.0.0.2 | admin | conexant |
NetMaster | 192.168.2.1 veya 192.168.0.1 | admin | password |
Quake | 10.0.0.2 | admin | epicrouter |
Onixon | 192.168.1.1 | root | root |
Origo Wireless | 10.0.0.2 | admin | kont2004 |
Origo | 192.168.2.1 | admin | admin |
Paradigm | 10.0.0.2 | admin | epicrouter |
Pikatel | 192.168.7.1 | DSL | DSL |
Pikatel ComboMax | 192.168.1.1 | admin | password |
Philips SNA6500 | 192.168.2.1 | boş bırakınız | admin |
Philips SNC6500 | 192.168.2.1 | boş bırakınız | admin |
Pti 840 | 10.0.0.2 | admin | epicrouter |
Pronets | 10.0.0.2 | admin | conexant |
Siemens | 192.168.254.254 | siz belirlersiniz | siz belirlersiniz |
SMC | 192.168.2.1 | boş bırakınız | smcadmin |
Sonicwall | 192.168.1.1 | admin | password |
Speedstream | 192.168.254.254 | admin | siz belirlersiniz |
Speedcom | 10.0.0.2 | admin | conexant |
SpeedTouch | 10.0.0.138 | siz belirlersiniz | siz belirlersiniz |
SpeedTouch 330 | 10.0.0.138 | siz belirlersiniz | siz belirlersiniz |
Thomson | 10.0.0.138 | siz belirlersiniz | siz belirlersiniz |
Tecom | 192.168.1.1 | root | root |
ZTE XDSL | 192.168.2.1 | admin | ttnet |
ZTE ZXDSL | 192.168.1.1 | ZXDSL | ZXDSL |
C:\Windows\Installer klasörü, bilgisayarımıza yüklenen programlara ait MSI ve MSP uzantılı kurulum dosyalarını barındırmaktadır. Yüklenen herhangi bir programı kaldırsanız bile bu programa ait MSP veya MSI dosyaları bu klasörde halen durmaktadır. Bu da gereksiz yere bilgisayarınızda alan kaplamaya neden olmaktadır. Burada bulunan tüm dosyalar gereksizdir diyemeyiz. Mevcut kurulu programların çalışması için burada bulunan dosyalara ihtiyac duyulmaktadır. Amacımız bilgisayarımızdan kaldırdığımız programların atıklarını temizlemektir.
Gereksiz olan dosyaların tespitini ise rahatlıkla yapamamaktayız. Çünkü klasörü incelediğinizde anlamsız isimlendirilmiş MSI ve MSP uzantılı dosyalarla karşılaşacaksınız. Burada tavsiye edebileceğimiz en kullanışlı uygulama PatchCleaner. Bu uygulama sayesinde bilgisayarınızda sildiğiniz ama halen Installer klasöründe listelenen gereksiz dosyaların tespitini hızlı şekilde gerçekleştirebilirsiniz. Uygulamayı indirmek için linke tıklayın.
Uygulamayı indirip kurduğunuzda aşağıdaki gibi bir ekranla karşılaşacaksınız.
Yukarıdaki ekran görüntüsünde gördüğünüz gibi 7.86 GB lık 128 adet dosya gereksiz yere bilgisayarımda alan kaplamakta. Bu dosyalara yönelik yapılabilecek Move ve Delete gibi iki seçenek sunulmaktadır. Delete butonuna tıkladığınızda Installer klasörü altındaki gereksiz dosyaların silinmesi sağlanmaktadır. Move butonuna tıklandığında ise bu dosyaların bilgisayarda farklı bir konuma taşınması sağlanmaktadır.
]]>PDO, PHP ile veritabanı arasında bir bağlantıyı temsil eder. PDOStatement ise herhangi bir sorguyu çalıştırdıktan sonra dönen sonuç kümesini temsil eder. PDOException, PDO tarafından oluşturulan hatayı temsil eder.
Bu makalemizde yapılacak örneği MySQL veritabanı kullanarak gerçekleştireceğiz. Örnek olarak ülkelerin tutulduğu bir tablo oluşturalım. Bu tablo içerisine de o ülkelere ait popülasyon bilgilerini örnek olarak girelim.
DROP TABLE IF EXISTS ulkeler; CREATE TABLE ulkeler(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT, ad VARCHAR(255), populasyon INT); INSERT INTO ulkeler(ad, populasyon) VALUES('China', 1382050000); INSERT INTO ulkeler(ad, populasyon) VALUES('India', 1313210000); INSERT INTO ulkeler(ad, populasyon) VALUES('USA', 324666000); INSERT INTO ulkeler(ad, populasyon) VALUES('Indonesia', 260581000); INSERT INTO ulkeler(ad, populasyon) VALUES('Brazil', 207221000); INSERT INTO ulkeler(ad, populasyon) VALUES('Pakistan', 196626000); INSERT INTO ulkeler(ad, populasyon) VALUES('Nigeria', 186988000); INSERT INTO ulkeler(ad, populasyon) VALUES('Bangladesh', 162099000); INSERT INTO ulkeler(ad, populasyon) VALUES('Nigeria', 186988000); INSERT INTO ulkeler(ad, populasyon) VALUES('Russia', 146838000); INSERT INTO ulkeler(ad, populasyon) VALUES('Japan', 126830000);
Bu komutla birlikte ulkeler adında bir tablo oluşturup içerisine veriler eklendi.
PDO da yaygın olarak kullanılan query() metodu ile veritabanına direkt sorgu atılmakta ve tekil sonuç dönmektedir. Dönen sonuca ulaşmak için fetch() metodu kullanılmaktadır.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $stm = $pdo->query("SELECT VERSION()"); $version = $stm->fetch(); echo $version[0] . PHP_EOL; ?>
Yukarıdaki örnek sorgu ile veritabanına ait versiyon bilgisi çekilmektedir. Örnek sorguda ilk satırda tanımlanan $dsn bilgisi hangi veritabanına bağlanılacağına yönelik bilgi içermektedir.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim";
Sorguda göründüğü üzere localhost üzerinde çalışan mysql veritabanına bağlanılacak. Bağlantılacak veritabanının ismini de veritabanım olarak belirledik. Daha sonrasında username ve password bilgileri alttaki satırlarda girilmektedir. Sonuç olarak aşağıdaki şekilde bir sorgu sonucu ile karşılaşmaktayız.
5.7.22-0ubuntu0.16.04.1
PDO da önemli bir yere sahip olan exec() metodu, yapılan sorgulama sonucu etkilenen sorgu sayısını geri dönmektedir.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $nrows = $pdo->exec("DELETE FROM ulkeler WHERE id IN (1, 2, 3)"); echo "Etkilenen kayıt sayısı: $nrows"; ?>
Yapılan sorgulama ile ulkeler tablosundan 1,2,3 idlerine sahip kayıtların silinmesi sağlamaktadır. Sonuç olarak ise örneğin üç kayıt silindiği için Etkilenen kayıt sayısı: 3 gibi bir sonuç dönecektir.
PDO yapısında PDO::FETCH_ASSOC, PDO::FETCH_NUM ve PDO::FETCH_BOTH şeklinde üç farklı fetch kurgusu bulunmaktadır. PDO::FETCH_BOTH default olarak tanımlı olan tanımlamadır. PDO::FETCH_ASSOC tanımında, dönen dizin elemanının sütün adına göre dönmesi sağlanmaktadır. PDO::FETCH_NUM tanımında, dönen dizin elemanı ise sütun numarasına göre dönecek şekilde ayarlanmaktadır.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $stm = $pdo->query("SELECT * FROM ulkeler"); $rows = $stm->fetchAll(PDO::FETCH_NUM); foreach($rows as $row) { printf("$row[0] $row[1] $row[2]\n"); } ?>
Yapılan sorgulamada dikkat ederseniz veriler $row[0], $row[1] ve $row[2] olarak çekilmektedir ve dönen içerikte veritabanından id, ad, populasyon alanlarına ait veriler listelenecektir.
Aşağıdaki sorguda ise direkt veritabanında kayıtlı olan sütun ismine göre verilerin çekilmesi sağlanmaktadır. Bunun için PDO::FETCH_ASSOC metodunu kullanmaktayız.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $stm = $pdo->query("SELECT * FROM ulkeler"); $rows = $stm->fetchAll(PDO::FETCH_ASSOC); foreach($rows as $row) { printf("$row['id'] $row['ad'] $row['populasyon']\n"); } ?>
SQL sorguları genellikle dinamik olarak oluşturulur. Sorgulamada setlenecek olan parametreler kullanıcı tarafından belirlenir. Ancak burada en önemli konu setlenilecek olan parametreleri bindValue() ve bindParam() gibi metodlar üzerinden gerçekleştirmeniz. Çünkü veritabanına bağlantıların gerçekleştirildiği kurgularda güvenlik en sorunlu olan kısımdır. Parametrik olan sorgular çoğunlukla veritabanına SQL injection gerçekleştirilmesi gibi sorunlara sebep olabilmektedir.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $id = 5; $stm = $pdo->prepare("SELECT * FROM ulkeler WHERE id = ?"); $stm->bindValue(1, $id); $stm->execute(); $row = $stm->fetch(PDO::FETCH_ASSOC); echo "Id: " . $row['id'] . PHP_EOL; echo "Ad: " . $row['ad'] . PHP_EOL; echo "Popülasyon: " . $row['populasyon'] . PHP_EOL; ?>
Bu sorgu ile idsi 5 olan kaydın çıktısı dönecektir. Aşağıda ekranda görüntülenecek olan veri şu şekilde olacaktır;
Id: 5 Ad: Brazil Popülasyon: 207221000
Aynı sorguyu bindParam() metodu ile gerçekleştirelim. Burada yapılacak sorgulamaya göre numerik olarak tanımlama yerine key- value olarak tanımlama gerçekleştirilmektedir.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $id = 5; $stm = $pdo->prepare("SELECT * FROM ulkeler WHERE id = :id"); $stm->bindParam(":id", $id, PDO::PARAM_INT); $stm->execute(); $row = $stm->fetch(PDO::FETCH_ASSOC); echo "Id: " . $row['id'] . PHP_EOL; echo "Ad: " . $row['ad'] . PHP_EOL; echo "Popülasyon: " . $row['populasyon'] . PHP_EOL; ?>
Dikkat ederseniz artık id olarak tanımlama yapılıp, parametrelerde id'ye göre setlemeler gerçekleştirilmektedir. Aslında bu yöntem bindValue metodundan daha kullanışlı ve güvenilirdir. Tavsiyemiz kodlamalarınızda bunu kullanmanızdır. Zaten sonuç olarak elde edilecek ekran görüntüsü yukarıda görüntülenen çıktıdan farklı olmayacaktır.
lastInsertId() metodu bizlere veritabanına eklenen herhangi bir veri olduğu zaman eklenen verinin rowId bilgisini dönmektedir. Bu veri çoğu zaman projemizde ilişkili veritabanını kurgusunu ayarlamada kullanılmaktadır. En güzel yani tekrardan select ile veritabanına sorgu atmamıza gerek kalmamakta, performans olarak baya etkin bir sonuç sunmaktadır.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Japan', 81050000)"); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Mexico', 550000)"); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Tunis', 938050000)"); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Benin', 182050000)"); $rowId = $pdo->lastInsertId(); echo "Son eklenen row id: $rowId\n"; ?>
Gördüğünüz gibi yapılan sorgulama ile birlikte ulkeler veritabanına 4 ayrı kayıt ekledik. Bu kayıtlarında eklenmesinin ardından kayda ait id numarası ekrana aşağıdaki şekilde gelecektir.
Son eklenen row id: 12
Transaction tanım olarak veritabanı işlemlerinde gerçekleştirilen unique birimdir. Özellikle birden fazla bağlantılı olan global projelerde bu kullanım önemli bir yer tutmaktadır. Çünkü yapılacak olan işlemler commit ve rollback isimli metodlarla desteklenmekte ve yapılan işlemlerin tümünün gerçekleştirilmesi garanti hale getirilmektedir.
<?php $dsn = "mysql:host=localhost;dbname=veritabanim"; $user = "kullanici"; $passwd = "abc123"; $pdo = new PDO($dsn, $user, $passwd); try { $pdo->beginTransaction(); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Japan', 81050000)"); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Mexico', 550000)"); $pdo->exec("INSERT INTO ulkeler(ad, populasyon) VALUES('Tunis', 938050000)"); $pdo->commit(); } catch(Exception $e) { $pdo->rollback(); throw $e; } ?>
Bu örnekte gördüğünüz gibi ulkeler veritabanına 3 yeni kayıt eklemeye çalışıyoruz. Öncelikle beginTransaction() metodu ile birlikte yeni bir transaction oluşturulması sağlandı. Yazılan kodlamada ya hep ya hiç kurgusuna göre kodumuz çalışacaktır. Yani çalıştırılan sorguda herhangi bir yerde sorun ortaya çıkarsa rollback ile geri dönecek ve kayıtlar veritabanına kayıt edilmeyecektir.
]]>Her domain kaydı esnasında domainin hak sahibini, finansal ve teknik sorumlusunu belirlemek için oluşturulan, domain alımlarında ilgili firma tarafından talep edilen ve içerisinde kişisel veya firmaya ait alınan bir domain ise firma ismi, telefon, e-mail ve adres bilgilerini barındıran bilgiler bütününe whois bilgisi denir.
Whois sorgulama, yetkilendirilmiş ip adresleri üzerinden ilgili Registry firmasından (Godaddy gibi) veya whois sunucusuna, güvenlik şartlarını tahsis ettiği veri tabanı üzerine bilgilerin yazılması ile gerçekleştirilir.
Bazı domainlerin kimlik bilgileri domaini alan kullanıcılar tarafından gizlenebilmektedir. Bu durum domain whois protection olarak anılır. Whois protection’a sahip alan adlarının sahiplerine veya finansal ya da teknik yöneticilerine ulaşmak için whois bilgisinin gizliliğini üstlenen vekil adresine bildirimde bulunmak gerekir.
Her whois protection servis sağlayıcı, ICANN kuralları gereği kendisi üzerinden iletilen bildirimleri kimliğini gizlediği alan adının gerçek sahibine ulaştırmak zorundadır. Bu zorunlulukta beyan esas kabul edildiğinden whois bilgisi gizlenen alan adlarının gerçek sahibine ulaşmak için iletişim bilgilerinin doğruluğu ve güncelliği öncelikle ilgili alan adının sahibinin sorumluluğundadır.
Hazırladığımız araç ile sorgulamak istediğiniz alan adına ait ayrıntılı detaya whois sorgulama linkinden erişebilirsiniz.
]]>Pandemi sürecinde en çok oynadığım oyunlardan birisi puzzle tipindeki oyunlardı. Bu oyunlarda dikkatimi çeken ve eksikliğini hissettiğim özelliklerin listesini oluşturup yeni bir uygulama yazma fikrini gerçekleştirip PuzzImage uygulamamızı yayına aldık.
Uygulamayı indirmek için linkine tıklayabilirsiniz.
]]>
- Uygulamamız şimdilik sadece Türkçe, İngilizce, Fransızca ve Arapça dillerini desteklemektedir.
- Uygulamamız tamamen ücretsizdir.
- Uygulamada hesap oluşturup lider tablosunda kendinize de bir yer açabilirsiniz.
- Basitten zora doğru 110 farklı seviyede puzzle listelenmektedir. Uygulamamız offline olarakda çalışmaktadır.
Makalemizde PHP programlamada yaygın olarak kullanılan bazı methodlar ile alakalı bilgi verip örnekler gerçekleştireceğiz.
echo komutu, tanımlı olan herhangi bir textin ekrana basılmasında kullanılmaktadır. Aslında kullanımı oldukça yaygın bir fonksiyondur.
$text = 'Süper Kupayı Fenerbahçe aldı.'; echo $text;
echo $text, kodu ile ekrana $text içerisinde tanımlı olan ifadenin basılması sağlanmaktadır. Burada unutulmaması gereken konu ekrana basılacak olan ifadenin text olmasıdır. Eğer array tarzı bir içeriğin ekrana basılması gerekirse print_r() methodunu kullanmanız gerekmektedir.
print_r komutu, herhangi bir array içerisinde tanımlı bir içerik varsa bunun ekrana basılmasında kullanılmaktadır.
$renkler = array("sarı","mavi","kırmızı", "yeşil"); print_r($renkler);
print_r($renkler), kodu ile ekrana $renkler dizin içerisinde tanımlı olan renklerin basılması sağlanmaktadır. Örneğin bu komutta ekrana Array ( [0] => red [1] => yellow [2] => pink ) verisi basılacaktır.
str_replace komutu, adından da anlaşıldığı üzere herhangi bir text üzerinde değiştirilmesini istediğiniz bir ifade varsa onu değiştirmede kullanılmaktadır;
$text = 'Süper Kupayı Fenerbahçe aldı.'; $degisim = str_replace('Fenerbahçe', 'Galatasaray', $text); echo $degisim;
str_replace('Fenerbahçe', 'Galatasaray', $text), kod satırında gördüğünüz üzere ilk parametre text içerisinde aranacak kelimeyi ifade etmektedir. İkinci parametre ise eğer aranan kelime bulunursa yerine konulacak olan ifadeyi temsil etmektedir. Kodlama sonucunda ortaya çıkacak olan text 'Süper Kupayı Galatasaray aldı.' şeklinde olacaktır.
explode komutu, text içerisinde geçen ifadeleri belirlenen ayraçlara göre bölmede kullanılmaktadır. Örneğin text içerisinde geçen cümleleri ayrı ayrı dizi elemanları içerisine aktarmak istiyorsanız '.' ayracını aşağıdaki şekilde kullanmanız yeterli olacaktır.
$text = "Ahmet bugün okula gelmedi. Evini aradık kimse cevap vermiyor. Çok merak ediyorum"; $ayrilmis = explode(".", $text); print_r($ayrilmis);
explode(".", $text), kod satırında gördüğünüz üzere ilk parametre ayrıştırıcı olarak kullanılan terimi ifade etmektedir. İkinci parametre ise ifadenin kendisini temsil etmektedir. Kodlama sonucunda ortaya çıkacak olan text Array ( [0] => Ahmet bugün okula gelmedi [1] => Evini aradık kimse cevap vermiyor [2] => Çok merak ediyorum ) şeklinde olacaktır. Dikkat ederseniz burada echo methodu yerine print_r metodunu kullandık. Yukarıda da belirtiğimiz üzere array yani dizileri ekrana basarken print_r metodunu kullanmanız gerekmektedir.
implode komutu, array yani dizi içerisinde tanımlı olan değişkenlerin text olarak birleştirilmesinde kullanılmaktadır. Burada birleşme esnasında kullanılması planlanan ayraç ilk parametrede iletilmektedir.
$array = array("Ahmet bugün okula gelmedi.", "Evini aradık kimse cevap vermiyor.", "Çok merak ediyorum""); $text = implode(" ", $array); echo $text;
implode(" ", $array), kod satırında yukarıda array içerisinde tanımlı olan textlerin boşluk karakteri ile birleştirilmesi sağlanmaktadır. Kodlama sonucunda ortaya çıkacak olan text Ahmet bugün okula gelmedi. Evini aradık kimse cevap vermiyor. Çok merak ediyorum şeklinde olacaktır.
rand komutu, verilen minimum ve maksimum rakamlar arasında rastgele sayı oluşturmada kullanılmaktadır. Örneğin websitenizde rastgele sayılara dayalı bir oyun geliştirmek istiyorsanız rand metodundan yararlanabilirsiniz.
echo rand(0,10);
rand(0,10), komutu çalıştırıldığında 0 ile 10 rakamları arasında rastgele bir rakamın oluşturulup ekrana basılması sağlanmaktadır. Burada ilk parametre minimum rakamı, ikinci parametre ise maksimum olan rakamı temsil etmektedir. Örnek çıktı olarak 3, 8, 1 gibi rakamları rastgele görebilirsiniz.
eval komutu, string içerisinde tanımlı olan herhangi bir Php kodunun çalıştırılmasında kullanılmaktadır. Aşağıda yapacağımız örnekle bu komutun işlevinin daha anlaşılır olacağı malum.
$run = 'echo "Ahmet bugun okula gelmedi";'; eval($run);
eval($run), komutu çalıştırıldığında $run değişkeni içerisinde tanımlı olan echo metodunun çalıştırılması sağlanmaktadır. Artık bildiğiniz üzere echo komutu sadece ekrana veri basmada kullanılmakta. eval komutu da aynı işlemi gerçekleştirip ekrana "Ahmet bugun okula gelmedi" textini basacaktır.
die komutu, programın istediğiniz bir kod satırında durdurulmasını istediğinizde kullanılmaktadır. Örneğin yazdığınız PHP kodunda hangi dosyada sorunun kaynaklandığını bilemediğiniz durumlarda bu komutu aktif olarak kullanabilirsiniz. Satır satır kod parçacıkları içerisinde ilerleyip problemin neden kaynaklı olduğunu tespit edebilirsiniz.
.... ... .. die("burda"); echo "test";
die("burda"), komutu çalıştırıldığında bu kod satırına gelinceye kadar Php projeniz çalışacaktır. Ancak die komutu çalıştığı anda artık ekrana "burda" ifadesi yazılı bir text gözükecektir. die komutu altında bulunan echo metodu çalışmayacaktır.
]]>Uzun bir süredir üzerinde çalıştığımız günlük burç uygulamasını yayına aldık. Uygulamamızın en önemli çıkış noktası olan çoklu dil desteği özelliği, diğer burç uygulamaların önüne çıkmasına sebep olmaktadır.
Uygulamayı indirmek için linkine tıklayabilirsiniz.
Ayrıca uygulamamıza ait promo videoya aşağıdaki youtube videosu üzerinden ulaşabilirsiniz.
]]>
- Uygulamamız Türkçe, İngilizce, Fransızca, Rusça, Korece, Japonca, Çince, Almanca, Flemenkçe, Filipince, Taylanca benzeri yirmiden fazla dil desteklemektedir.
- Uygulamamızda ücretsiz olarak günlük bildirim özelliği bulunmaktadır.
- Her gün size özel şanslı numaralar listelenmekte, ayrıca renklerden de faydalanabilmektesiniz.
- Uyumlu burçlar özelliği ile birlikte her gün farklı burç uyumluluğuna yönelik bilgiler uygulamamız üzerinden sizlere sunulmaktadır.
- İletişim sayfası üzerinden gerçek zamanlı olarak astrologlara anlık mesajlar iletebilir ve onlardan gelen cevaplara karşılık verebilirsiniz.
Kaynakların yetersiz kalmaması ve kullanıcıların sunucuya erişebilmesi için, sunucularda işlem başına bellek kullanımını ve kullanılan belleği kontrol etmek genellikle önemlidir. Örneğin bir web sitesiniz var ve bu siteyi bir web sunucusu üzerinde çalıştırıyorsanız, sunucunun site ziyaretçilerine sorunsuz hizmet edebilmesi için yeterli belleğe sahip olması gerekmektedir. Aksi takdirde, bellek yetersiz kalıp trafik artışı olduğunda site çok yavaşlayabilir hatta siteniz çökebilir. Tıpkı masaüstü bilgisayarlarda karşılaşılan mavi ekranlar gibi ekranlarla karşılaşılabilirsiniz.
Şimdi bellek kontrolünde kullanılan beş önemli komutu detaylı şekilde madde madde inceleyelim.
free komutu, Linux üzerindeki bellek kullanımını kontrol etmek için kullanılan kullanımı en basit bir komuttur. Aşağıda komut kullanımı şu şekildedir;
root@yazilimdersi: free -m total used free shared buffers cached Mem: 7976 6459 1517 0 865 2248 -/+ buffers/cache: 3344 4631 Swap: 1951 0 1951
-m parametresi, tüm verileri MB cinsinden görüntülemede kullanılır. Sistemde yüklü olan toplam RAM miktarı 7976 MB yani 8GBdir. used sütununda, Linux tarafından kullanılan RAM miktarını (6.4 GB) civarında göstermektedir. Komut sonucu akan veri oldukça açıklayıcı aslında. İkinci satırda bulunan 4,6 GB'nin kullanılabilir olduğunu göstermektedir.
Linux işletim sistemi doğal yapısında herseyi cacheleyip daha performanslı bir kullanıma yönelik çalışmaktadır. İhtiyac olmadığı durumda cache üzerinden verilerin silinmesi de otomatik olarak işletim sistemi tarafından gerçeklenmektedir.
Son satır, bu durumda tamamen free olan swap bellektir.
Bellek kullanımını kontrol etmenin bir başka yoluda /proc/meminfo dosyasını okumaktır. /proc dosya sisteminde gerçek dosyalar içermediğini bilin. Daha çok core ve sistem hakkında dinamik bilgiler içeren sanal dosyalardan oluşmaktadır.
root@yazilimdersi: cat /proc/meminfo MemTotal: 8167848 kB MemFree: 1409696 kB Buffers: 961452 kB Cached: 2347236 kB SwapCached: 0 kB Active: 3124752 kB Inactive: 2781308 kB Active(anon): 2603376 kB Inactive(anon): 309056 kB Active(file): 521376 kB Inactive(file): 2472252 kB Unevictable: 5864 kB Mlocked: 5880 kB SwapTotal: 1998844 kB SwapFree: 1998844 kB Dirty: 7180 kB Writeback: 0 kB AnonPages: 2603272 kB Mapped: 788380 kB Shmem: 311596 kB Slab: 200468 kB SReclaimable: 151760 kB SUnreclaim: 48708 kB KernelStack: 6488 kB PageTables: 78592 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 6082768 kB Committed_AS: 9397536 kB VmallocTotal: 34359738 kB VmallocUsed: 420204 kB VmallocChunk: 34359311 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 62464 kB DirectMap2M: 8316928 kB
MemTotal, MemFree, Buffers, Cached, SwapTotal, SwapFree alanlarına dikkat ederseniz free komutunda listelenen verilerle aynıdır. Bu komutta daha fazla bilgi verilmektedir.
s parametresi ile kullanılan vmstat komutu, proc komutuna çok benzer şekilde bellek kullanım istatistiklerini göstermektedir.
root@yazilimdersi: vmstat -s 8167848 K total memory 7449376 K used memory 3423872 K active memory 3140312 K inactive memory 718472 K free memory 1154464 K buffer memory 2422876 K swap cache 1998844 K total swap 0 K used swap 1998844 K free swap 392650 non-nice user cpu ticks 8073 nice user cpu ticks 83959 system cpu ticks 10448341 idle cpu ticks 91904 IO-wait cpu ticks 0 IRQ cpu ticks 2189 softirq cpu ticks 0 stolen cpu ticks 2042603 pages paged in 2614057 pages paged out 0 pages swapped in 0 pages swapped out 42301605 interrupts 94581566 CPU context switches 1382755972 boot time 8567 forks
Üstteki birkaç satır toplam belleği, boş belleği vb. kullanışlı verileri gösterir.
top komutu, genellikle işlem başına bellek ve CPU kullanımını kontrol etmek için kullanılır. Bununla birlikte, toplam bellek kullanımını da rapor eder ve toplam RAM kullanımını izlemek için kullanılır. Komut çıktısında bulunan header alanı sonuca yönelik detaylı bilgileri içermektedir.
root@yazilimdersi: top top - 15:20:30 up 6:57, 5 users, load average: 0.64, 0.44, 0.33 Tasks: 265 total, 1 running, 263 sleeping, 0 stopped, 1 zombie %Cpu(s): 7.8 us, 2.4 sy, 0.0 ni, 88.9 id, 0.9 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem: 8167848 total, 6642360 used, 1525488 free, 1026876 buffers KiB Swap: 1998844 total, 0 used, 1998844 free, 2138148 cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2986 enlighte 20 0 584m 42m 26m S 14.3 0.5 0:44.27 yakuake 1305 root 20 0 448m 68m 39m S 5.0 0.9 3:33.98 Xorg 7701 enlighte 20 0 424m 17m 10m S 4.0 0.2 0:00.12 kio_thumbnail
Komut çıktısında başlıktaki KiB Mem ve KiB Swap satırlarını görebilirsiniz. Hafızanın toplam, kullanılan ve boş miktarlarını gösterirler. Arabellek ve önbellek bilgileri, free komut gibi burada da mevcuttur.
top komutuna benzer şekilde, htop komutu da çeşitli diğer ayrıntılarla birlikte bellek kullanımını göstermektedir.
Üstteki alanda RAM ile birlikte Cpu kullanımını ve buna karşılık gelen swap kullanımını göstermektedir.
Böylelikle bellek kontrolünde kullanabileceğimiz en basit ve kullanışlı komutları gözden geçirmiş olduk. Burada önemli olan bu verilerin periyodik olarak sunucularınızda kontrol edilmesi ve gerektiği anda aksiyon alınmasıdır. Çünkü sunucularda bellekten kaynaklı herhangi bir sorun ile karşılaşıldığı anda sistemin çökmesi olası durumlardandır.
]]>Bu tarz bir durumla karşılaştığınızda izlemeniz gereken adımlar şu şekildedir;
1. Öncelikle Masaüstünde change-background.bat isminde bir dosya oluşturalım.reg add "HKEY_CURRENT_USER\Control Panel\Desktop" /v Wallpaper /t REG_SZ /d [DOSYA_PATHI] /f RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters
Yaptığımız işlem aslında registry key üzerinde güncelleme yaparak direkt olarak arka resmi atanmasına imkan sunmaktadır.
Yukarıdaki kodlamada [DOSYA_PATHI] alanına değiştirmek istediğiniz dosya pathini yapıştırmanız gerekmektedir.
İkinci satırda RUNDLL32.EXE komutu ile değiştirilen arka plan resminin anlık olarak yansıtılması sağlanmaktadır. Aksi takdirde üstteki kodlama çalıştırsanız bile arka plan resmini değiştirmeyecektir.
Komut satırında çalıştırılan kodlama herhangi bir tehlike arz etmemektedir. Değiştirilecek olan ekran resminin özelliklerinin uygun formatta bulunması önemlidir.
]]>Makalemizde detaylandırılacak olan popüler komutların listesinin tümüne aşağıdan erişebilirsiniz.
SSH Komutu | Açıklaması |
---|---|
ls |
Mevcut dizin altındaki dosyaların bilgilerini listeler. |
cd |
Dizin değiştirmede kullanılır. |
mkdir |
Yeni bir klasör oluşturmada kullanılır. |
touch |
Dosya oluşturmada kullanılır. |
rm |
Dosya silmede kullanılır. |
cat |
Dosya içeriğini görüntülemede kullanılır. |
pwd |
Mevcut dizinin full pathini gösterir. |
cp |
Dosya veya dizin kopyalamada kullanılır. |
mv |
Dosya veya dizin taşımada kullanılır. |
grep |
Dosya içerisinde veya komutta herhangi bir text arama yapılırken kullanılır. |
find |
Dosya ve dizin içerisinde aramada kullanılır. |
vi/nano |
Kullanışlı text editorleri açmada kullanıır. |
history |
Çalıştırılan son 50 komutu listeler. |
clear |
Komut ekranını temizler. |
tar |
Ziplenmiş dosyayı açmada kullanılır. |
wget |
Dosyaları internetten indirmede kullanılır. |
du |
Dosya boyutunu görüntülemede kullanılır. |
Şimdi yukarıda listelediğimiz komutları detaylı şekilde madde madde inceleyelim.
ls komutu, tüm dosyaları ve dizinleri listelemede kullanılır. Terminalde ls komutunu girdikten sonra şuna benzer bir çıktı ile karşılaşacaksınız;
root@yazilimdersi:/home/yazilimdersi# ls var wwww html config vendor app controller
Bu komuta ek olarak aşağıdaki parametrelerle daha detaylı bilgiler alabilirsiniz;
- -l: Listelenen dosyaların detaylı bilgisi ile birlikte görüntülenir. Örneğin dosya boyutu, güncellenme zamanı, sahibi vs.
- -a: Gizlenen dosyalarında listelenmesinde kullanılır.
cd komutu, dosyalar arasında geçiş yapmak amacıyla kullanılır. Zaten bu komut ismini change directory ifadesinin baş harflerinden almaktadır. Çok basit ve kullanışlı bir komuttur. Tek yapmanız gereken gitmeniz gereken dosya pathini cd komutunun ardından yazmak;
cd [DOSYA_YOLU] // sunucunuza ait ana dizine erişmek için home yazmanı gerekir. cd home // ya da farklı bir dizin altındaki klasöre ulaşmak için bu dizini direk full path olarak yazabilirsiniz. cd /var/www/html/yazilimdersi/controller
Mevcut olan dizinden bir önceki dizine erişmek için .. (iki nokta) kullanmanız gerekmektedir.
root@yazilimdersi:/var/www/html/yazilimdersi/controller# cd .. root@yazilimdersi:/var/www/html/yazilimdersi#
mkdir komutu, dizin oluşturmak amacıyla kullanılır. Zaten bu komut Make Directory ifadesinin kısaltmasıdır. Komutun syntaxı şu şekildedir;
mkdir [DIZIN_ISMI] // Örneğin, "model" dizini oluşturmak istiyorsanız bu komutu yazmanız yeterli mkdir model
touch komutu, dosya oluşturmak amacıyla kullanılır. Komutun syntaxı şu şekildedir;
touch [DOSYA_ISMI] // Örneğin, "app.json" dosyası oluşturmak istiyorsanız bu komutu yazmanız yeterli touch app.json
rm komutu, dosya veya dizin silme amacıyla kullanılır. Dosya silmede kullanılan komutun syntaxı şu şekildedir;
rm [DOSYA_ISMI] // Örneğin, "app.json" dosyasını silmek istiyorsanız bu komutu yazmanız yeterli rm app.json
Eğer bir dizini yani klasörü silmeyi amaçlıyorsanız -r parametresi ile rm komutunu çağırmanız gerekmektedir.
rm -r /var/www/html/yazilimdersi/app
cat komutu, dosya içeriğini görüntülemede kullanılır. Dosya içeriği görüntülemede kullanılan komutun syntaxı şu şekildedir;
cat [DOSYA_ISMI]
Eğer birden fazla dosyanın içeriğini birleştirip tek bir dosya oluşturmayı düşünüyorsanız aşağıdaki komutu çalıştırabilirsiniz;
cat dosya1.txt dosya2.txt > finaldosya.txt
Bu komutla birlikte dosya1.txt ve dosya2.txt içeriği merge edilip finaldosya.txt oluşturulup içerisine yapıştırılır.
pwd komutu, mevcut dizine ait full pathi görüntülemede kullanılır;
root@yazilimdersi:/var/www/html/yazilimdersi/controller# pwd /var/www/html/yazilimdersi/controller
Linux sunucularda en kullanışlı komutlardan birisi pwd komutudur. Çünkü herhangi bir path üzerinde bir işlem gerçekleştirmeden önce ilgili pathin doğrulanmasını kolaylaştırmaktadır.
cp komutu, dosya veya dizin kopyalama işlemlerinde kullanılır. Bu komutun syntaxı şu şekildedir;
cp [PARAMETRELER] [KAYNAK_DOSYA_DIZIN] [HEDEF_DOSYA_DIZIN] // Örneğin "dosya1.txt" dosyamız var ve bunun kopyasını aynı dizinde "dosya2.txt" ismiyle kopyalamak istiyorsunuz cp dosya1.txt dosya2.txt // Eğer direkt dizinin bir kopyasını başka bir dizin altında kopyalamak istiyorsanız cp /var/www/htm/yazilimdersi/app /home/user/project
cp komutunda bulunan parametre alanı zorunlu değildir. Bu alana gelebilecek parametreler şu şekildedir;
- -f: Eğer hedef dosya veya klasöre yazma yetkimiz yoksa onu silip yeni dosya veya dizin oluşturulmasını sağlar.
- -u: Eğer kaynak dosya hedef dosyadan daha güncel ve yeni ise kopyalamayı gerçekleştirmede kullanılır.
- -n: Eğer aynı isimde bulunan dosya varsa üzerine yazılmasını engeller.
- -a: Dosyaları arşivlemede kullanılır.
Dosyaların çoğaltılmasının aksine, klasörlerin kopyalanması için -R seçeneğini kullanmanız gerekir. Bu parametre dizin içindeki tüm klasörlerin ve dosyaların kopyalanmasına izin verir.
cp -R /var/www/html/yazilimdersi/app /home/etc/
mv komutu, aslında cp komutuna benzer bir komuttur. Tek fark ise, mv komutunda dosyalar veya dizinler direkt taşınmaktadır. Yani kaynak dizinde herhangi bir dosya kalmayacaktır bu komut çağrıldıktan sonra;
mv [KAYNAK_DOSYA_DIZIN] [HEDEF_DOSYA_DIZIN] // Örneğin "dosya1.txt" dosyamız var ve bunu /home/yazilimdersi/app dizini altına taşıyalım mv dosya1.txt /home/yazilimdersi/app // Eğer direkt bir dizini başka bir dizin altına kopyalamak istiyorsanız mv /var/www/htm/yazilimdersi/app /home/user/project
grep komutu, text ile arama işlemlerinde kullanılır.
grep 'Exception' error.log
Yukarıdaki komut error.log dosyası içerisinde 'Exception' ifadesi geçen satırları dönmektedir. Örnek sonuç aşağıdaki şekilde görüntülenir;
root@yazilimdersi:/var/www/html/yazilimdersi/logs# grep 'Exception' error.log NullPointer Exception has been crashed on this line ZeroDivider Exception ..... MathException .... Exception ...
Eğer yapılan aramalarda küçük büyük harf ayrımı olmadan arama yapılsın istiyorsanız -i parametresini kullanmanız gerekmektedir.
find komutu, girilen kriterleri (ad, boyut, dosya türü, vb.) karşılayan dosyaları aramada kullanılır. Komutun syntax yapısı şu şekildedir;
find [ARAMA_DIZINI] [PARAMETRELER] [ARANACAK_KELIME][ARAMA_DIZINI] aramanın yapılacağı dizini belirlemede kullanılmaktadır;
[PARAMETRELER] arama esnasında kullanılacak olan alanı belirler;
- / (slash) Tüm dizinde arama yapmada kullanılır.
- . (dot) Mevcut dizinde arama yapmada kullanılır.
- ~ (tilde) home dizini altında arama yapmada kullanılır.
[ARANACAK_KELIMA] arama yapmada kullanılacak ifadedir.
- -name Dosya ismine göre aramada kullanılır.
- -user Kullanıcıya göre arama yapmada kullanılır.
- -size Dosya boyutuna göre aramada kullanılır.
find / -name “index”
Yukarıdaki komut isminde "index" geçen ve sunucuda bulunan tüm dosyalarda tarama yapılmasında kullanılmaktadır.
vi ve nano, Linux sunucularda kullanılan popüler text editorlerdir.
// vi editor ile dosya çağrılırsa vi [DIZIN_ISMI] //nano editor ile dosya çağrılırsa nano [DIZIN_ISMI]
Eğer komutta geçen dizin ismi yok ise, editor otomatik olarak bu dosyayı oluşturup açacaktır.
history komutu, Linux sunucularda çalıştırılan son komutların listelenmesinde kullanılır. Bu komutta ikinci parametre olarak görüntülenecek komutların sayısı girilmelidir
root@yazilimdersi:/var/www/html/yazilimdersi/controller# history 5 vi index.txt find / -name "file" cp /var/wwww/html/yazilimdersi /home/etc ls pwd
Yukarıdaki komutta son 5 komutun listelenmesi sağlanmıştır.
clear komutu, terminal ekranında görüntülenen görüntü kirliliğini ortadan kaldırmada kullanılır.
tar komutu, .tar.gz dosyalarını oluşturmada veya paketlenmiş dosyadan çıkarmada kullanılmaktadır. Linux sunucularda aktif olarak kullanılan bir komuttur.
// Herhangi bir dizini .tar.gz formatında arşivlemek istiyorsanız bu komutu kullanmalısınız tar cvzf archive.tar.gz /var/www/html/yazilimdersi // .tar.gz formatındaki bir arşivi açmak için bu komutu kullanmalısınız tar xvzf archive.tar.gz
Yukarıdaki komutlarda dikkat ederseniz farklı harf dizimleri ile komutlar çalıştırılmaktadır.
- x: tar komutuna arşivlenmiş dosyayı açmasını söyler.
- c: tar komutuna dosyanın arşivlemesi gerektiğini söyler.
wget komutu, internetde bulunan herhangi bir dosyaya erişip indirmede kullanılır. Örneğin bir websitesinde bulunan dosyaya erişip komutun çalıştırıldığı dizine indirilmesini aşağıdaki komutla sağlarız.
wget http://google.com
du komutu, dosya ve dizinlerin boyutunu görüntülemede kullanılmaktadır. Zaten bu komut Disk Usage ifadesinin kısaltmasıdır. Komutun syntaxı şu şekildedir;
du [DIZIN_PATH]
Ancak bu komutun daha okunur olmasını sağlamak için -h parametresini eklememiz gerekmektedir.
root@yazilimdersi:/var/www/html/yazilimdersi/controller# du -h /var/www/html/yazilimdersi/app 120M /var/html/yazilimdersi/app/controllers 10K /var/html/yazilimdersi/app/models 125K /var/html/yazilimdersi/app/views 11K /var/html/yazilimdersi/app/config ..... ...]]>
Yapacağımız örnek projede json formatta response dönen ücretsiz api çağrısından (Space Flgihts APIsi üzerinden) veriyi parse edip RecyclerView componenti kullanarak listelemeye çalışacağız.
1. File => New Project seçeneğine tıklayalım. Sonrasında açılan ekranda Empty Activity seçeneğini seçip Next butonuna tıklayalım.dependencies { ......... // gson kütüphanesini ekleyelim implementation 'com.google.code.gson:gson:2.8.6' // retrofit kütüphanelerini ekleyelim implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' }5. Projemizde internet üzerinden API çağrısı yapılacağı için AndroidManifest.xml dosyasında INTERNET iznini almamız gerekmektedir kullanıcıdan.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="info.yazilimdersi.sampleretrofit"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".activity.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Projemizde ücretsiz ve herhangi bir api keye ihtiyacımız olmayan Spaceflight News API servisini kullanacağız. Projenin başında model dizini altında oluşturduğumuz Article, Launch ve Event sınıflarını neden oluşturduğumuza bakalım.
Get Articles linkine tıklağınızda açılan sayfada Try Out butonuna basıp response dönen içeriği inceleyelim.
package info.yazilimdersi.sampleretrofit.model; import com.google.gson.annotations.SerializedName; import java.util.ArrayList; import java.util.List; public class Article { @SerializedName("id") private String id; @SerializedName("title") private String title; @SerializedName("url") private String url; @SerializedName("imageUrl") private String imageUrl; @SerializedName("newsSite") private String newsSite; @SerializedName("summary") private String summary; @SerializedName("publishedAt") private String publishedAt; @SerializedName("updatedAt") private String updatedAt; @SerializedName("featured") private Boolean featured; @SerializedName("launches") private List<Launch> launches = new ArrayList<Launch>(); @SerializedName("events") private List<Event> events = new ArrayList<Event>(); public String getTitle() { return title; } public String getSummary() { return summary; } public List<Launch> getLaunches() { return launches; } public String getImageUrl() { return imageUrl; } }7. Article sınıfı içerisinde tanımladığımız ve makale ile ilişkili herhangi bir event yada launch olup olmadığını belirlemede kullanılan Launch ve Event sınıflarının içerisine aşağıdaki kod parçacıklarını ekleyelim.
package info.yazilimdersi.sampleretrofit.model; import com.google.gson.annotations.SerializedName; public class Launch { @SerializedName("id") private String id; @SerializedName("provider") private String provider; }
package info.yazilimdersi.sampleretrofit.model; import com.google.gson.annotations.SerializedName; public class Event { @SerializedName("id") private String id; @SerializedName("provider") private String provider; }
Projemizde atılacak olan API requestlerinin ana yapısı olan Retrofit'e ait kurguyu api dizini altında bulunan ApiClient.java dosyası olarak belirledik. Burada Retrofit Builder sınıfını kullanarak API yapısının oluşturulması sağlanacaktır. Ayrıca API ya ait ana linkinde burada tanımlanması gerekmektedir.
import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class ApiClient { public static final String BASE_URL = "https://test.spaceflightnewsapi.net/api/v2/"; private static Retrofit retrofit = null; public static Retrofit getClient() { if (retrofit==null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); } return retrofit; } }
Endpointler proje süresince kullanılacak olan ve farklı sınıflardan da erişimi kolay olacak şekilde interface yapısına uygun şekilde ayarlanır. Ek olarak, yapılan API çağrılarında dönüş verisi her zaman Call<Article> gibi parametreleştirilmiş bir Call<T> nesnesidir.
import info.yazilimdersi.sampleretrofit.model.Article; import retrofit2.Call; import retrofit2.http.GET; public interface ApiInterface { @GET("articles") Call<List<Article>> getArticles(); }
Böylelikle Retrofit ile yapılan çağrıda https://test.spaceflightnewsapi.net/api/v2/articles linkine GET ile request atılmış olacaktır.
Retrofit kütüphanesinde HTTP requestlerine yönelik (GET, POST, PUT etc.) gibi annotationlar ve (@Query, @Path, @Body etc.) gibi özel annotationlar bulunmaktadır. Endpointin talebine uygun olarak bu tanımlamaları gerçekleştirmeniz gerekecektir. Kısaca specific annotationları özetleyelim;
- @Path: Endpoint linkinde iletilmesi gereken herhangi bir parametre olduğunda kullanılır Örneğin; /article/{id} ile request atılmak istenildiğinde @Path kullanılarak id verisi setlenebilir.
- @Query: Endpointe bağlı olarak iletilecek olan query parametrelerinde kullanılır. Örneğin; /articles?order=id&isfeatured=true tarzı requestleri sağlar.
- @Body: POST ile iletilecek olan body verisinde kullanılır.
- @Header: Atılacak olan requestde headerde iletilmesi gereken herhangi bir bilgi varsa kullanılır.
MainActivity.java sınıfı içerisinde ilk API çağrımızı gerçekleştirelim. Gerçekleştirilecek API çağrısı ile birlikte SpaceFlight API üzerinden yayımlanan makalelere erişmemiz gerekecektir.
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.util.List; import info.yazilimdersi.sampleretrofit.R; import info.yazilimdersi.sampleretrofit.api.ApiClient; import info.yazilimdersi.sampleretrofit.api.ApiInterface; import info.yazilimdersi.sampleretrofit.model.Article; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class); Call<List<Article>> call = apiService.getArticles(); call.enqueue(new Callback<List<Article>>() { @Override public void onResponse(Call<List<Article>> call, Response<List<Article>> response) { List<Article> articles = response.body(); Log.d("SampleRetrofit", "Makale sayısı : " + articles.size()); } @Override public void onFailure(Call<List<Article>>call, Throwable t) { Log.e("SampleRetrofit", t.toString()); } }); } }
Retrofit kütüphanesi API requestini background thread üzerinden atıp dönen response ile birlikte failure veya success durumuna göre UI threadini bilgilendirecektir. Projeyi Debug ile çalıştırdığımızda aşağıdaki şekilde verilerin model içerisine nasıl enjekte edildiğini gözlemleyebilirsiniz.
Makaleler artık API üzerinden bize ulaşmaktadır. Sırada yapılacak işlem makalelerin önyüzde görüntülenmesini sağlayacak kodlamayı tanımlamaktır. Öncelikle build.gradle dosyasına RecyclerView'e ait dependecynin eklenmelidir. Ayrıca Glide kütüphanesini kullanarak makaleye ait resimleri yükleyeceğiz.
dependencies { ..... //recyclerview kütüphanesi implementation 'androidx.recyclerview:recyclerview:1.1.0' //glide kütüphanesi implementation 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' }
Hazırlanacak listelemede makaleye ait resim, başlık, içerik ve events sayısının görüntülenmesi sağlanacaktır. Bunun için layout içerisinde 1 adet ImageView, 3 adet TextView ayarlamamız gerekecektir.
8. colors.xml dosyasını açıp uygulamada kullanılacak renklere ait verileri aşağıdaki şekilde ekleyelim.<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="orange">#FF3909</color> <color name="colorAccentDark">#00B482</color> <color name="colorBlack">#555555</color> <color name="colorWhite">#FFFFFF</color> <color name="colorGrey">#707070</color> <color name="colorGreyLight">#8A8A8A</color> </resources>9. list_item_article.xml dosyasını açıp uygulamada kullanılacak renklere ait verileri aşağıdaki şekilde ekleyelim.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/movies_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="72dp" android:orientation="horizontal" android:padding="16dp"> <ImageView android:id="@+id/articleImageView" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginRight="16dp" android:layout_centerInParent="true" android:scaleType="centerCrop" /> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/titleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:paddingRight="16dp" android:textColor="@color/colorBlack" android:textSize="16sp" android:textStyle="bold" /> <TextView android:id="@+id/summaryTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="3" android:paddingRight="16dp" android:textColor="@color/colorGreyLight" /> <TextView android:id="@+id/launchesTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/colorPrimaryDark" </LinearLayout> </LinearLayout>10. ArticlesAdapter.java sınıfı içerisine API den dönen makalelerin verileri işlenmelidir.
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import java.util.List; import info.yazilimdersi.sampleretrofit.R; import info.yazilimdersi.sampleretrofit.model.Article; public class ArticlesAdapter extends RecyclerView.Adapter<ArticlesAdapter.ArticleViewHolder> { private List<Article> articles; private Context context; public static class ArticleViewHolder extends RecyclerView.ViewHolder { LinearLayout articleLinearLayout; TextView titleTextView; TextView summaryTextView; TextView launchesTextView; ImageView articleImageView; public ArticleViewHolder(View v) { super(v); articleLinearLayout = (LinearLayout) v.findViewById(R.id.articleLinearLayout); titleTextView = (TextView) v.findViewById(R.id.titleTextView); summaryTextView = (TextView) v.findViewById(R.id.summaryTextView); launchesTextView = (TextView) v.findViewById(R.id.launchesTextView); articleImageView = (ImageView) v.findViewById(R.id.articleImageView); } } public ArticlesAdapter(List<Article> articles, Context context) { this.articles = articles; this.context = context; } @Override public ArticlesAdapter.ArticleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_article, parent, false); return new ArticleViewHolder(view); } @Override public void onBindViewHolder(ArticleViewHolder holder, final int position) { holder.titleTextView.setText(articles.get(position).getTitle()); holder.summaryTextView.setText(articles.get(position).getSummary()); holder.launchesTextView.setText(articles.get(position).getLaunches().size() + " launches"); Glide.with(context).load(articles.get(position).getImageUrl()).into(holder.articleImageView); } @Override public int getItemCount() { return articles.size(); } }11. Son olarak MainActivity.java sınıfı içerisine RecyclerView oluşturup parametrik olarak Article sınıfını iletmemiz gerekecektir.
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.articlesRecyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class); Call<List<Article>> call = apiService.getArticles(); call.enqueue(new Callback<List<Article>>() { @Override public void onResponse(Call<List<Article>> call, Response<List<Article>> response) { List<Article> articles = response.body(); recyclerView.setAdapter(new ArticlesAdapter(articles, getApplicationContext())); } @Override public void onFailure(Call<List<Article>>call, Throwable t) { Log.e("SampleRetrofit", t.toString()); } }); } }
Böylelikle Retrofit kullanarak oluşturduğumuz örnek projeyi tamamladık. Artık elimizde json dönen bir API üzerinden parsing gerçekleştirebilen bir kodlama bulunmakta. Projeye ait ekran görüntüsü şu şekildedir;
Bu makalemizde text to speech özelliğine ait bir örnek proje oluşturup, kütüphanenin sunduğu fonksiyonlara bağlı olarak dil değişikliği, okuma hızı ve vurgu seviyesine göre denemeler gerçekleştireceğiz.
Hazırlayacağımız örnekte basit bir editText alanı ile kullanıcının dinamik olarak içerik girebilmesi ve sonrasında girilen içeriğin eklenecek butona tıklanıldığında okunabilmesi hedeflenmektedir.
1. File => New Project seçeneğine tıklayalım. Sonrasında açılan ekranda Empty Activity seçeneğini seçip Next butonuna tıklayalım.public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {4.Interface implementasyonundan sonra zaten uygulama bize onInit(int) metodunu implement etmemize yönelik uyarı vermektedir. Aşağıda bulunan kodlamayı MainActivity sınıfına yapıştıralım.
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { private TextToSpeech textToSpeech; private Button speakButton; private EditText textEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textToSpeech = new TextToSpeech(getApplicationContext(), this, "com.google.android.tts"); setVolumeControlStream(AudioManager.STREAM_MUSIC); speakButton = (Button) findViewById(R.id.speakButton); textEditText = (EditText) findViewById(R.id.textEditText); speakButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { speakOut(); } }); } @Override public void onDestroy() { // Don't forget to shutdown tts! if (textToSpeech != null) { textToSpeech.stop(); textToSpeech.shutdown(); } super.onDestroy(); } @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { int result = textToSpeech.setLanguage(Locale.US); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e("TTS", "Bu dil desteklenmemektedir"); } else { speakButton.setEnabled(true); speakOut(); } } else { Log.e("TTS", "Initilizationda sorunla karşılaşıldı!"); } } private void speakOut() { String text = textEditText.getText().toString(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Bundle bundle = new Bundle(); bundle.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC); textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, bundle, null); } else { HashMapparam = new HashMap<>(); param.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC)); textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, param); } } }
Kodlamada eklenen kodları dilerseniz adım adım inceleyelim.
textToSpeech = new TextToSpeech(getApplicationContext(), this, "com.google.android.tts");kullanılacak olan TTS objesinin tanımlanması gerçekleştirilmektedir. Interface kullanılarak sınıfta onInit() metodu ilmeplement edildiği için this parametresi kullanılmıştır.
setVolumeControlStream(AudioManager.STREAM_MUSIC);metodu ile uygulamanın audio kontrolunu alması sağlanmaktadır.
int result = textToSpeech.setLanguage(Locale.US);metodu ile de seslendirmede kullanılacak olan dili setlememiz sağlanmaktadır. Şu anda ne yazıkki Türkçe dil desteği henüz default olarak TTS kütüphanesine eklenmemiştir. Ancak Almanca, Fransızca, Çince, Korece gibi farklı dilleri setleyebilirsiniz.
private void speakOut() { String text = textEditText.getText().toString(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Bundle bundle = new Bundle(); bundle.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_MUSIC); textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, bundle, null); } else { HashMap<String, String> param = new HashMap<>(); param.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC)); textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, param); } }speakOut() metodunda gördüğünüz üzere iki farklı Android SDK versiyonuna göre seslendirme çalışmaktadır. Android Lollipop ve üzeri versiyonarda Bundle uzerinden textlerin iletimi sağlanmaktadır. 5. Uygulamanın arayüz dosyası olan activity_main.xml dosyasına aşağıdaki kodlamayı yapıştıralım.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/icon_app_logo" /> <EditText android:id="@+id/textEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Hello World!" /> <Button android:id="@+id/speakButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/speak" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>Böylelikle uygulamamızı tamamlamış olduk. Burada söz etmemiz gereken iki önemli fonksiyon bulunmaktadır.
Son olarak uygulamaya ait arayüz aşağıdaki şekildedir;
- setPitch: Bu metod ile konuşma sırasındaki vurgu seviyesini ayarlayabilirsiniz.
- setSpeechRate: Bu method kullanılarak konuşma hızını ayarlayabilirsiniz. Default olarak 1 seviyesindedir. Ancak konuşmanın daha hızlı olmasını isterseniz bunu 2 veya 3 olarak setlemeniz yeterli olacaktır.
Daha önceki bir makalemizde PHP'de mail() metodunu kullanarak email gönderimini sizlerle paylaşmıştık. Ancak mail() metodu güvenilebilir ve kullanışlı bir metod değildir. Çünkü mail metodu ile iletilen mailler direkt sunucu üzerinden iletildiği için Spam klasörüne düşme ihtimali yüksektir. Ayrıca mail içerisine image veya herhangi bir dosya eklemek isterseniz bunu mail() metodu ile sağlayamazsınız.
Bu makalemizde popüler email sağlayıcısı olan Gmail'i kullanarak nasıl mail gönderebileceğimizi adım adım sizlerle paylaşacağız. Öncelikle SMTP kullanımının faydalarını nelerdir onu öğrenelim
- Daha komplex ve iyi email gönderimi
- Kendi sunucumuza kurulum gerektirmez
- Karalisteye düşme ihtimaliniz daha düşük olacaktır. Bu nedenle emailleriniz spam klasörüne düşmez veya seyrek düşer.
Gmail SMTP kullanılarak iletilecek maillerin limiti günlük 100 maildir. Eğer bu limite ulaşırsanız, bir sonraki güne kadar beklemeniz gerekmektedir. Gmail'in mail limitleri ile alakalı daha detaylı bilgiye sahip olmak isterseniz bu linke tıklayabilirsiniz.
Gmail hesabını iki şekilde SMTP olarak kullanabiliriz;
- Daha az güvenli uygulamalara erişim özelliğini kullanarak
- Uygulama şifresi kullanarak
Bu yöntemde öncelikle Gmail ayarlarında bulunan daha az güvenli uygulamalara erişim iznini açmanız gerekmektedir. Google bu ayarı açmanızla birlikte artık mail adresinize ait orijinal şifreyi kullanarak mail atılmasına izin verdiğinizi kabul etmektedir. Bu ayarı gerçekleştirmek için linke tıklayabilirsiniz.
Uygulama şifresi özelliği ile Gmail geçici bir şifre tanımlamanıza imkan sunmaktadır. Burada izlenmesi gereken adımlar şu şekildedir;
a. Öncelikle Gmail hesabınıza ait güvenlik sayfasına buradan tıklayarak erişiniz.
b. Bu sayfada aşağıda bulunan Google'da oturum açma alanına geliniz. Bu alanda bulunan 2 adımlı doğrulama seçeneği kapalı ise açmanız gerekmektedir. Bunun için 2 Adımlı Doğrulama seçeneğine tıklayın.
c. Açılan sayfada Başlata basıp iki adımlı doğrulamada seçeceğiniz metodu belirleyin. Burada SMS, Arama, Telefonunuzdaki Gmail hesabı vs metodları bulunmaktadır. En pratik olan Gmail hesabı kurulu olan telefonunuza mobil bildirim gelmesi konusudur. Sonrasında ayrıca SMS veya telefon araması ile doğrulama yapmanız gerekmektedir.
Bu işlemin ardından 2 adımlı doğrulama seçeneğiniz aktif hale gelmiştir. Ayrıca güvenlik sayfasınıza geri döndüğünüzde artık Uygulama şifreleri alanınında gözüktüğünü gözlemleyebilirsiniz. Güvenlik sayfasına erişim için buraya tıklayınız.
d. Uygulama şifreleri sayfasına buraya tıklayarak erişebilirsiniz. Açılan sayfada sizden uygulama tipi ve cihaz seçimi talebinde bulunacaktır. Bunun önemli bir yanı yoktur. Genellikle uygulama tipi kısmına Diğer secip projemin ismini yazmaktayım. Böylelikle Gmail SMTP özelliğini farklı projelerde kullammak istediğimde farklı şifreler oluşturabilirim.
e. Diğer seçeneği seçilip uygulamanıza ait isim girdikten sonra Oluştur butonuna basınız. Sonrasında popup ekranda 16 karakterli uygulama şifreniz aşağıdaki şekilde görüntülenecektir. Bu şifreyi başkaları ile paylaşmayınız. Orjinal Gmail şifresinin görünmesi kadar güvenlik problemi içermez ancak bu bilgiye sahip olan herhangi bir kişi sizin adınıza SMTP üzerinden mail atabilir!
Böylelikle Gmail adresimizi direkt mail gönderimi yapacak şekilde ayarlamış olduk. İkinci method ile yapılan gönderimlerin ne kadar önemli olduğunu tekrardan vurgulamak istedim. Şimdi SMTP sunucularında gerekli config ayarları nelerdir. Onları inceleyelim. Gmail'e ait SMTP ayarları aşağıdaki gibidir;
- SMTP Sunucusu: smtp.gmail.com
- SMTP Kullanıcı Adı: Gmail adresiniz, örneğin [email protected]
- SMTP Şifresi: Gmail şifreniz veya uygulama şifreniz
- SMTP Port: 587 veya 465
- TLS/SSL: Gerekli
Şu an elimizde kodlamada kullanılacak olan SMTP sunucuya ait config bilgileri bulunmakta. En popüler PHP kütüphanesi olan PHPMailer ile SMTP ayarını yapıp mail atabileceğimiz örnek bir kod geliştirelim. Aşağıdaki adımları izleyerek projemizi oluşturalım.
a. Öncelikle bu linke tıklayarak PHPMailer kütüphanesinin Github kodlarına erişelim. Buradaki Github kodlarını Clone or Download seçeneğine tıklayarak bilgisayarınıza indirin.
b. İndirme işleminin ardından indirilen projede examples dizini altında gmail.phps dosyası bulunmaktadır. Bu dosya içerisinde halihazırda tanımlanmış Gmail ayarları bulunmaktadır.
use PHPMailer\PHPMailer\PHPMailer; require '../vendor/autoload.php'; //Create a new PHPMailer instance $mail = new PHPMailer; //Tell PHPMailer to use SMTP $mail->isSMTP(); //Enable SMTP debugging // 0 = off (for production use) // 1 = client messages // 2 = client and server messages $mail->SMTPDebug = 2; //Set the hostname of the mail server $mail->Host = 'smtp.gmail.com'; // use // $mail->Host = gethostbyname('smtp.gmail.com'); // if your network does not support SMTP over IPv6 //Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission $mail->Port = 587; //Set the encryption system to use - ssl (deprecated) or tls $mail->SMTPSecure = 'tls'; //Whether to use SMTP authentication $mail->SMTPAuth = true; //Username to use for SMTP authentication - use full email address for gmail $mail->Username = "[email protected]"; //Password to use for SMTP authentication $mail->Password = "yourpassword"; //Set who the message is to be sent from $mail->setFrom('[email protected]', 'First Last'); //Set an alternative reply-to address $mail->addReplyTo('[email protected]', 'First Last'); //Set who the message is to be sent to $mail->addAddress('[email protected]', 'John Doe'); //Set the subject line $mail->Subject = 'PHPMailer GMail SMTP test'; //Read an HTML message body from an external file, convert referenced images to embedded, //convert HTML into a basic plain-text alternative body $mail->msgHTML(file_get_contents('contents.html'), __DIR__); //Replace the plain text body with one created manually $mail->AltBody = 'This is a plain-text message body'; //Attach an image file $mail->addAttachment('images/phpmailer_mini.png'); //send the message, check for errors if (!$mail->send()) { echo "Mailer Error: " . $mail->ErrorInfo; } else { echo "Message sent!"; }
Bu projede Gmail SMTP sunucunun sorunsuz çalışması için bize ait olan kullanıcı adı (username), şifre (password) ve email alıcı adresi (email recipient address) verilerinin değiştirilmesi gerekmektedir. Ayrıca dosya ismini gmail.php olarak güncellemeniz gerekmektedir.
Artık projemiz mail gönderimine uygun şekilde. Tek yapmanız gereken proje kodlarını web sunucunuzda bir uygulama altına koymanız. Sonrasında http://projeniz.com/PHPMailer-master/examples/gmail.php linki gibi bir link üzerinden kodunuzu çalıştırdığınızda mail atma işleminin başarılı şekilde gerçekleştiğini gözlemleyebilirsiniz.
Dünyanın en popüler blog yapısı olan Wordpress'te bir websiteniz varsa ve mail gönderimi yapmak istiyorsanız, WP Mail SMTP pluginini indirip kullanabilirsiniz.
a. Öncelikle yapmanız gereken Wordpress sitenize ait admin sayfasına giriş yapınız.
b. Sonrasında solda bulunan menüden Eklentiler >> Ekle sekmesine tıklayınız.
c. WP Mail SMTP diye arama yaparak eklentiyi yükleyiniz.
d. Yükleme işleminin ardından Eklentiler > Yüklü Eklentiler sayfasını açıp Ayarlar‘a tıklayın ve WP Mail SMTP ayarlarına erişelim.
e. Açılan ayarlar sayfasında bize ait olan SMTP bilgilerinin eksiksiz olarak girilmesi gerekmektedir.
Yukarıda rakamlarla tanımlanan alanların bilgileri şu şekildedir;
- SMTP Host – smtp.gmail.com olarak giriniz.
- SMTP Port – Varsayılan Gmail SMTP sunucu portu (SSL için 465 ve TSL için 587’dir).
- Şifreleme – Şifreleme kullanmak her zaman önerilir. Yukarıda seçtiğiniz porta uygun şekilde seçiniz.
- Doğrulama – SMTP doğrulama gerekli olduğundan Evet’i seçin.
- Kullanıcı adı – Gmail adresiniz.
- Şifre – Gmail şifreniz veya Uygulama şifreniz.
Yukarıdaki alanları doğru şekilde doldurduktan sonra Değişiklikleri Kaydedin butonuna tıklayınız. Sonrasında yapılan ayarların doğru olduğundan emin olmak için WP Mail SMTP plugininin sunduğu Send Test ekranı üzerinden test mesajı atabilirsiniz.
Böylelikle makalemizde Gmail hesabımızı nasıl SMTP server olarak ayarlayıp projelerimizde kullanacağımızı öğrendik. Ayrıca PHPMailer veya WP Mail SMTP kullanarak mail gönderimlerinin nasıl gerçekleştirildiğinin adım adım inceleme imkanı bulduk. ]]>
public class MainActivity extends ListActivity {4. Şimdi sıra listelemede görüntülenecek seçeneklerin res => values dizini altında list_data.xml dosyası içerisine eklenmesinde.
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="adobe_products"> <item>Android</item> <item>Objective C</item> <item>Swift</item> <item>Kotlin</item> <item>React Native</item> <item>Xamarin</item> <item>Ionic</item> <item>Sencha Touch</item> </string-array> </resources>5. Seçeneklerin gösteriminde kullanılacak sayfanın tasarımı için res => layout dizini altında list_item.xml dosyası içerisine aşağıdaki kod parçasının eklenmesi gerekmektedir.
<?xml version="1.0" encoding="utf-8"?> <!-- Single List Item Design --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/label" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip" android:textSize="16dip" android:textStyle="bold" > </TextView>6. Şimdi MainActivity sınıfı içerisine aşağıdaki kod parçalarını yapıştıralım. Yazdığımız kod sayesinde listeleme için eklediğimiz seçeneklerin görüntülenmesi sağlanmaktadır.
package info.yazilimdersi.listview; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] mobileAppFrameworks = getResources().getStringArray(R.array.mobile_app_frameworks); this.setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, mobileAppFrameworks)); } }
Projeyi çalıştırdığımızda aşağıdaki ekran görüntüsü ile karşılaşacaksınız. Ekran görüntüsünde gördüğünüz üzere popüler mobil frameworkler listelenmektedir.
package info.yazilimdersi.listview; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] mobileAppFrameworks = getResources().getStringArray(R.array.mobile_app_frameworks); this.setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, mobileAppFrameworks)); ListView lv = getListView(); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String product = ((TextView) view).getText().toString(); Intent i = new Intent(getApplicationContext(), DetailItemActivity.class); i.putExtra("product", product); startActivity(i); } }); } }8. DetailItemActivity sınfı için kullanılacak arayüzü res => layout dizini altında detail_item.xml isminde oluşturalım.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/product_label" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="25dip" android:textStyle="bold" android:gravity="center" android:padding="10dip" android:textColor="#000000"/> </LinearLayout>
Hazırlanan arayüzde seçilen seçeneğin yeni Activity içerisinde gösterimini sağlayalım. Burada önemli olan yukarıda eklenen kodlama ile Intent ile seçili textin DetailItemActivity aktarımını sağladık. getIntent() ile Activityler arası iletilen verilerin yakalanması sağlanmaktadır.
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.TextView; public class DetailItemActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.detail_item); TextView txtProduct = (TextView) findViewById(R.id.product_label); Intent i = getIntent(); String product = i.getStringExtra("product"); txtProduct.setText(product); } }Son olarak oluşturulan yeni Activity sınıfının AndroidManifest.xml dosyası içerisinde tanımlanması gerekmektedir. Aksi takdirde uygulamanız crash edecektir.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="info.yazilimdersi.listview"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DetailItemActivity" android:label="Detail Item"></activity> </application> </manifest>
Android işletim sistemi, uygulamalarda default olarak İngilizceyi ana dil olarak kabul eder ve uygulama içeriklerini res ⇒ values ⇒ strings.xml'den yükler. Uygulamanıza ait yeni bir dil tanımlamanız gerektiğinde tanımlayacağınız dile ait ISO kodunu values dizinin ardına eklemeniz gerekmektedir. Örneğin uygulamamıza Türkçe ve Arapça dil desteği eklemeyi planladığımız için Türkçe için values-tr, Arapça dili içinse values-ar dizinlerini oluşturup içerisine strings.xml dosyasını yerleştirmemiz gerekmektedir.
Lokalizasyon yapısı ise aşağıdaki adımlara göre çalışmaktadır;
- Kullanıcı cihaz dilini Ayarlar ⇒ Dil ve Giriş seçeneğinden değiştirdiğinde, Android işletim sistemi uygulamadaki uygun dil kaynaklarını kontrol eder.(Farzedelim kullanıcı Arapça'yı seçiyor)
- Uygulama seçilen dili destekliyorsa, Android projede bulunan values-(ISO Dil Kodu) klasöründeki strings.xml dosyasına bakar. (Arapça için values-ar/string.xml'de bulunan içerikleri yükler)
- Eğer Arapça dil dosyasına eksik olan herhangi bir değer varsa values/strings.xml dosyası içerisinde bulunan içeriği gösterir.
Bundan dolayı, values/stings.xml dosyasının içeriği tüm text değerlerini içermesi gerekmektedir. Aksi takdirde, uygulamanın hata alacaktır.
Uygulamanızda dikkat etmeniz gereken en önemli konulardan birisi static textlerin tanımlamaları her zaman strings.xml dosyası içerisinde olmalıdır.<string name="enter_email">Enter email address</string>Tanımlanan textleri uygulamamıza ait layoutlarda aşağıdaki şekilde çağırabiliriz.
<TextView ... android:text="@string/enter_email" />
Android Studio'da File ⇒ New ⇒ New Project seçeneğine tıklayıp Empty Activity ile yeni bir proje oluşturalım.
Sonrasında values dizini altında strings.xml dosyası içerisine aşağıdaki tanımlamaları gerçekleştirelim. Bizde default olarak İngilizceyi farz edip ona göre stringleri tanımlayalım.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Sample Localization App</string> <string name="action_settings">Settings</string> <string name="welcome">Welcome!</string> <string name="email">Email Address</string> <string name="password">Password</string> <string name="login">Login</string> <string name="signup">Don\'t have account? Sign Up</string> </resources>Bu işlemden sonra Türkçe ve Arapça dil desteği için values-ar ve values-tr dizinleri oluşturup içerisine strings.xml dosyalarını koymamız gerekmektedir. Bu işlemleri gerçekleştirdikten sonra proje diziniz şu şekilde olacaktır.
Şimdi öncelikle Türkçe strings.xml dosyasına çeviri içeriklerini girelim.
Türkçe values-tr/strings.xml<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Örnek Lokalizasyon Uygulaması</string> <string name="action_settings">Ayarlar</string> <string name="welcome">Merhaba!</string> <string name="email">Email Adresi</string> <string name="password">Şifre</string> <string name="login">Giriş Yapın</string> <string name="signup">Herhangi bir hesabınız yokmu? Hesap Oluştur</string> </resources>Şimdi de Arapça dil desteği için values-ar/strings.xml dosyasına çeviri içeriklerini girelim.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">نموذج لتطبيق التعريب</string> <string name="action_settings">إعدادات</string> <string name="welcome">أهلا بك!</string> <string name="email">عنوان بريد الكتروني</string> <string name="password">كلمه السر</string> <string name="login">تسجيل الدخول</string> <string name="signup">ليس لديك حساب؟ سجل</string> </resources>Şimdi sırada uygulamamıza ait activity_login.xml sayfasına aşağıdaki kod parçalarını yapıştırmamızda. Login sayfamız basit bir email ve şifre arayüzüne sahip olacaktır.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorAccent"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="40dp" android:text="@string/welcome" android:textColor="@color/colorWhite" android:textSize="45dp" android:textStyle="bold" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@color/colorWhite" android:orientation="vertical" > <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:background="@null" android:hint="@string/email" android:padding="5dp" android:singleLine="true"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@null" android:hint="@string/password" android:inputType="textPassword" android:padding="5dp" /> </LinearLayout> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="25dp" android:background="@color/colorPrimary" android:text="@string/login" android:textColor="@color/colorWhite"/> </LinearLayout> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/signup" android:layout_alignParentBottom="true" android:gravity="center_horizontal" android:layout_marginBottom="25dp" android:textColor="@color/colorWhite"/> </RelativeLayout>Şu anda Android Studio üzerinde layout kısmına kodlamanıza yapıştırmanızın ardından Design tabına geçtiğinizde aşağıdaki ekran görüntüsü ile karşılaşmanız gerekmektedir.
Burada Türkçe ve Arapça seçeneği listelenmektedir. Örnek olarak Türkçe dili seçildiğinde ekran görüntüsü aşağıdaki gibi olacaktır.
- Model: Model, uygulamanın verilerini tutar. Doğrudan view ile iletişim kurmaz. Genel olarak, verileri Observables aracılığıyla ViewModel'e aktarır.
- View: View, uygulamanın arayüzünü kapsamaktadır.
- ViewModel: Model ve View arasında bir köprü görevi görür. Modelden gelen datanın View'e aktarılmasından sorumludur. Verilerin anlık aktarımı için hook veya callback metodları kullanılmaktadır.
- Middle Layer'de Presenter yerine ViewModel kullanılmaktadır.
- Presenter, View'e ait referanslar tutar. Ancak ViewModelde buna gerek kalmamaktadır.
- Presenter, View'i klasik yolları kullanarak güncellemektedir.
- ViewModel, Model üzerinden gelen verileri iletebilmektedir.
- Presenter ve View 1'e 1 (one to one) ilişki içindedir.
- View ve ViewModelde ise 1'e çok yönlü (one to many) ilişki içindedir.
- ViewModel, View'un onu dinlediğini bilmez.
Android'de MVVM'yi uygulamanın iki yöntemi bulunmaktadır:
- Data Binding
- RX Java
Makalemize Data Binding yöntemini kullanarak devam edelim. Data Binding, verileri doğrudan xml dosyalar üzerinden bağlamak için Google tarafından tanıtılan bir kütüphanedir.
Şimdi MVVM'i kullanarak email ve password içeren basit bir login sayfası oluşturalım. Uygulamamızda View'e ait herhangi bir referans tutulmaksızın ViewModel üzerinden iletilen verinin nasıl gösterildiğini göreceğiz.İpucu: Herhangi bir referans tutulmadan bir sınıfa bildirimde bulunmak nasıl mümkün olabilir?
Bu işlem üç şekilde gerçekleştirilebilir;
- Çift Yönlü Data Binding kullanarak
- Live Data kullanarak
- RxJava kullanarak
Çift Yönlü Data Binding, uygulama arayüzünde bulunan nesnelerin verilerle çift taraflı haberleşmesine imkan sunan bir tekniktir. Bu tekniğe göre layout üzerinden ViewModel'e ve ViewModel üzerinden layouta data aktarımı sağlanabilmektedir.
Bizim örnek projemiz ise ViewModel üzerinden veri aktarımı ve yaşanan değişikliklerin Observer yapısı üzerinden yakalanmasını kapsamaktadır.
Bunun için BindingAdapter ve XML'de tanımlanan custom attributelere ihtiyacımız var. Binding Adapter, custom attribute üzerinde gerçekleşen değişiklikleri izleyecektir.
Projemizde klasör yapısını aşağıdaki şekilde kurgulayacağız. Projemizde sadece login sayfası kurguladığımızdan dolayı User modeli, LoginViewModel sınıfı ve LoginActivity yeterli olmaktadır.
android { dataBinding { enabled = true } }Eklenen kod parçası data bindingin projemizde aktif hale gelmesini sağlamaktadır.
implementation 'android.arch.lifecycle:extensions:1.1.0'
public class User { private String email; private String password; public User(String email, String password) { this.email = email; this.password = password; } public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } }Projemizde kullanılacak olan çift yönlü data binding işlemi yukarıda da dile getirdiğimiz gibi xml layout üzerinde tanımlanan viewlerin güncellenmesinde veya view üzerinde yapılan işlemin Model üzerine aktarımında kullanılmaktadır.
Çift yönlü data binding için kullanılan syntax @={variable} şeklindedir.
?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:bind="http://schemas.android.com/tools"> <data> <variable name="viewModel" type="yazilimdersi.info.example.samplemvvm.viewmodels.LoginViewModel" /> </data> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="8dp" android:orientation="vertical"> <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:padding="10dp" android:src="@drawable/icon_app_logo" /> <EditText android:id="@+id/inEmail" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Email" android:inputType="textEmailAddress" android:padding="8dp" android:text="@={viewModel.userEmail}" /> <EditText android:id="@+id/inPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:inputType="textPassword" android:padding="8dp" android:text="@={viewModel.userPassword}" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:background="@color/colorPrimaryDark" android:textColor="@color/colorWhite" android:onClick="@{()-> viewModel.onLoginClicked()}" android:text="LOGIN" bind:toastMessage="@{viewModel.toastMessage}" /> </LinearLayout> </ScrollView> </layout>Data Bindingde arayüzüne yönelik işlemlerde sayfanın en üst kısmında layout taglerinin tanımlanması gerekmektedir. Yukarıda yapılan tanımlamalar sonrasında ViewModel dataları direkt olarak arayüze bind edebilmektedir. Kodlamada gördüğünüz üzere ()-> viewModel.onLoginClicked() fonksiyonu LoginViewModel sınıfı içerisinde tanımlanmıştır. Kullanıcı login butonuna bastığı anda bu bilginin ViewModel e iletilmesi sağlanmaktadır. Ayrıca ViewModel üzerinden gelen verilerin view e aktarımına örnek olarak (bind:toastMessage="@{viewModel.toastMessage}" kullanımını inceleyebiliriz. toastMessage verisinde herhangi bir değişiklik olduğu takdirde view üzerinde bu mesajın gösterimini sağlanmaktadır.
import android.databinding.BaseObservable; import android.databinding.Bindable; import android.text.TextUtils; import android.util.Patterns; import com.android.databinding.library.baseAdapters.BR; import yazilimdersi.info.example.samplemvvm.model.User; public class LoginViewModel extends BaseObservable { private User user; private String successMessage = "Başarılı şekilde giriş yapıldı"; private String errorMessage = "Email veya Şifre hatalı"; @Bindable private String toastMessage = null; public String getToastMessage() { return toastMessage; } private void setToastMessage(String toastMessage) { this.toastMessage = toastMessage; notifyPropertyChanged(BR.toastMessage); } public void setUserEmail(String email) { user.setEmail(email); notifyPropertyChanged(BR.userEmail); } @Bindable public String getUserEmail() { return user.getEmail(); } @Bindable public String getUserPassword() { return user.getPassword(); } public void setUserPassword(String password) { user.setPassword(password); notifyPropertyChanged(BR.userPassword); } public LoginViewModel() { user = new User("",""); } public void onLoginClicked() { if (isInputDataValid()) setToastMessage(successMessage); else setToastMessage(errorMessage); } public boolean isInputDataValid() { return !TextUtils.isEmpty(getUserEmail()) && Patterns.EMAIL_ADDRESS.matcher(getUserEmail()).matches() && getUserPassword().length() > 5; } }LoginViewModel sınıfımızı ViewModel üzerinden extend edebiliriz. Ancak amacımız login butonuna tıklanıldığında Toast mesajı gösterecek bir kurgu olduğundan BaseObservable sınıfını extend etmemiz daha iyi olacaktır.
toastMessage ile alakalı olarak ViewModel sınıfımızda getter ve setter methodlarını tanımlamamız gerekmektedir. settter methodu içerisinde notifyPropertyChanged metodunu çağırmamız gerekmekte. Böylelikle datamızın değiştiği bilgisini View ile paylaşmış oluyoruz. View de yaptığımız tanımlamalara göre aksiyon alacaktır. BR sınıfı proje rebuild edilirken otomatik olarak data binding kütüphanesi tarafından oluşturulmaktadır.
LoginActivity.java sınıfı içinde aşağıdaki kod parçasını yapıştıralım.import androidx.appcompat.app.AppCompatActivity; import androidx.databinding.BindingAdapter; import androidx.databinding.DataBindingUtil; import yazilimdersi.info.example.samplemvvm.R; import yazilimdersi.info.example.samplemvvm.databinding.ActivityLoginBinding; import yazilimdersi.info.example.samplemvvm.viewmodels.LoginViewModel; public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityLoginBinding activityLoginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login); activityLoginBinding.setViewModel(new LoginViewModel()); activityLoginBinding.executePendingBindings(); } @BindingAdapter({"toastMessage"}) public static void runMe(View view, String message) { if (message != null) Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show(); } }
DataBinding librarysi sayesinde ActivityLoginBinding sınıfı otomatik olarak oluşturulmaktadır. @BindingAdapter methodunda tanımlı olan toastMessage güncellendiği anda içerisinde bulunan kod parçası trigger etmektedir.
Böylelikle ViewModel, yukarıdaki kodlamada görüldüğü üzere View üzerindeki işlemleri izleyerek Model'i güncellemektedir. Ayrıca Model, notifyPropertyChanged metodunu kullanarak View'i trigger edebilmektedir.
Uygulamamıza ait ekran görüntüsü aşağıdaki şekildedir.
Bu kısımda, Php Composer'ı Linux, MacOS ve Windows gibi işletim sistemlerinde nasıl kuracağınızı göstereceğiz.
Composer'ı Linux ve MacOS işletim sistemine sahip sunucu veya bilgisayarlara yüklemede kullanılan komutlar aynıdır. Composer'ı sisteminize nasıl kuracağınızı öğrenmek için aşağıdaki adımları izleyin;
#composerin resmi websitesinden indirilmesi php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
#yükleyici dosyanın doğrulanması php -r "if (hash_file('sha384', 'composer-setup.php') === 'c31c1e292ad7be5f49291169c0ac8f683499edddcfd4e42232982d0fd193004208a58ff6f353fde0012d35fdd72bc394') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
Yukarıdaki komuttaki uzun karakter dizisi ("c31c1e292ad…") yükleyicinin imzasıdır. Composer'ın her yeni sürümü çıktığında bu kod değişir. Bu nedenle, bu sayfaya tıklayarak en son SHA-384'ü getirdiğinizden emin olun.
#Local Kurulum php composer-setup.php
#Global Kurulum php composer-setup.php --install-dir=/usr/local/bin --filename=composerKurulum başarılı gerçekleştirildiği takdirde aşağıdaki ekranla karşılaşacaksınız...
All settings correct for using Composer Downloading... Composer (version 1.10.5) successfully installed to: /usr/local/bin/composer
#Kurulum dosyasının silinmesi php -r "unlink('composer-setup.php');"
#Komut satırına bu komutu girin composerÇalışan komut sonrasında aşağıdaki şekilde bir ekranla karşılaşmanız gerekmektedir.
______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ / __ `__ / __ / __ / ___/ _ / ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / ____/____/_/ /_/ /_/ .___/____/____/___/_/ /_/ Composer version 2.0.4 2020-11-02 16:20:11
Windows makinesinde Composer kurulumu Linux ve MacOS sistemlere göre biraz farklıdır. Yazılımın indirilmesi ve kurulması için herhangi bir komut satırı talimatı gerekli değildir.
Aşağıdaki adımları izleyerek kurulumu gerçekleştirelim.
composer
Artık Windows bilgisayarınızda composer yüklü. Yükleyici, composer'i PATH değişkeninize otomatik olarak ekleyecektir. Artık komut istemini açabilir ve yazılımı her yerden çalıştırabilirsiniz.
Şu ana kadar makalemizde composer kurulumunun nasıl yapıldığını sizlerle paylaştım. Şimdi ilginç kısım geliyor - PHP projenizde composer'i nasıl kullanabiliriz. Bunu sağlamak için projenizde composer.json dosyası oluşturmanız gerekir. Bu dosya, projeniz için indirilmesi gereken paketleri (kütüphaneleri) içerir. Ayrıca bu dosya, projenizle ile alakalı sürüm uyumluluğunu da kontrol eder. Eğer eski bir kütüphane veya paket kullanıyorsanız, composer.json'ın gelecekteki sorunları önlemek için size haber vereceği anlamına gelmektedir.
composer.json dosyasını manual olarak sizde oluşturabilirsiniz. Ancak herşeyin otomatik olarak sunulduğu sistemde en iyisi tüm çalışmaların otomatik olarak kontrol edilmesidir.
Örnek bir proje oluşturarak composer.json'ın kullanılışını görelim. Projemiz, herhangi bir kod çalıştırıldığında geçen süreyi gösteren bir zamanlayıcı olsun. Aşağıdaki adımları izleyerek proje dosyalarını oluşturalım.
#phpzamanlayici klasörü oluşturun mkdir phpzamanlayici
#phpzamanlayici klasörünü girin cd phpzamanlayici
Gördüğünüz gibi, arama sonucu birkaç zamanlayıcı paketi listelendi ve her birinin bir adı ve ne işe yaradığına dair küçük bir açıklaması vardır. Bu örnekte, en çok indirilen ve GitHub yıldızlarının çoğuna sahip olduğu için phpunit/php-timer'ı seçiyoruz.
#php-timer kütüphanesinin kurulumu composer require phpunit/php-timerKomut sonrasında aşağıdaki şekilde bir ekran ile karşılaşmanız gerekmektedir.
Using version ^1.0 phpunit/php-timer
Yukarıdaki komutu çalıştırdıktan sonra, proje dizininizde iki yeni dosya (composer.json ve composer.lock) ve vendor adlı bir klasör olacaktır. vendor dizini, composer'in tüm paketlerinizi ve bağımlılıklarınızı depolayacağı dizindir.
Projede herşey yolunda görünüyor. Şu anda yapmanız gereken tek şey phptimer bağımlılığının PHP kodunuza yüklemesidir. Otomatik yüklemeyi kullanmak için, komut dosyanızda yeni değişkenler bildirmeden veya başlatmadan önce aşağıdaki satırı yazın;
require '/vendor/autoload.php'Daha iyi anlamanız için size bir örnek göstereceğim. projenizde demo.php adında bir sınıf oluşturun.
nano demo.phpBu dosya içerisine aşağıdaki kod satırını yapıştıralım.
<?php require __DIR__ . '/vendor/autoload.php' Timer::start(); $time = Timer::stop(); var_dump($time); print Timer::secondsToTimeString($time); ?>Sonrasında aşağıdaki komut satırını çalıştırın;
php demo.phpTerminalde aşağıdaki sonuçların görüntülenmesi gerekmektedir.
double(1.0893424438611E-5) 0 ms
Son olarak, paketlerinizi nasıl güncelleyeceğinizi bilmeniz gerekir. Bu, iki şekilde gerçekleştirilebilir:
composer update
composer update vendor/package vendor2/package2Komutta yer alan vendor/package alanını güncellemek istediğiniz paket ismi ile değiştirmeyi unutmayın.
Ülkelerin koronavirüsten kaynaklı gerçekleşen gerçek zamanlı vaka sayıları listelenmektedir. Hazırladığımız arayüz sayesinde herhangi bir ülke adı ile arama yaparak koronavirus vaka sayılarına rahatlıkla erişebilirsiniz.
]]>Bu makalede, Android işletim sistemli cihazlarda veritabanının temellerini SQLite kullanarak oluşturacağımız Notlarım uygulaması ile öğreneceğiz.
Veri tabanı depolamasının Android uygulamalarda nasıl çalıştığını göstermek üzere basit bir Notlarım uygulaması oluşturacağız. Bu uygulama kullanıcının yeni not girebildiği, silebildiği veya güncelleme yapabildiği bir ekrandan oluşan basit bir uygulamadan oluşacaktır. Uygulama ile alakalı ekran görüntüleri şu şekildedir;
Hadi Android Studio'da notlarım uygulamasını oluşturmaya başlayalım.
1. Android Studio'da File ⇒ New Project seçeneğini seçip, templates olarak görüntülenen seçeneklerden Basic Activity olanı seçerek yeni bir Android proje oluşturun.
2. app dizini altında bulunan build.gradle dosyasını açın ve RecyclerView kütüphanesini ekleyin. Bu kütüphane notların listelenmesinde kullanılacaktır.
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // .. implementation 'com.android.support:recyclerview-v7:26.1.0' }
3. colors.xml, dimens.xml ve strings.xml dosyalarına aşağıdaki kod parçalarını ekleyin.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#455399</color> <color name="colorPrimaryDark">#455399</color> <color name="colorAccent">#00c6ae</color> <color name="msg_no_notes">#999</color> <color name="hint_enter_note">#89c3c3c3</color> <color name="timestamp">#858585</color> <color name="note_list_text">#232323</color> </resources>
<resources> <dimen name="fab_margin">16dp</dimen> <dimen name="activity_margin">16dp</dimen> <dimen name="dot_margin_right">10dp</dimen> <dimen name="msg_no_notes">26sp</dimen> <dimen name="margin_top_no_notes">120dp</dimen> <dimen name="lbl_new_note_title">20sp</dimen> <dimen name="dimen_10">10dp</dimen> <dimen name="input_new_note">20sp</dimen> <dimen name="dot_height">30dp</dimen> <dimen name="dot_text_size">40sp</dimen> <dimen name="timestamp">14sp</dimen> <dimen name="note_list_text">18sp</dimen> </resources>
<resources> <string name="app_name">Notlarım</string> <string name="action_settings">Ayarlar</string> <string name="activity_title_home">Notlar</string> <string name="msg_no_notes">Hernangi bir not bulunamadı!</string> <string name="lbl_new_note_title">Yeni Not</string> <string name="lbl_edit_note_title">Notu Güncelle</string> <string name="hint_enter_note">Notunu gir!</string> </resources>
4. Projede database, database/model, utils ve view isimlerinde dosya paketleri oluşturun. Yapılan düzenlemelerden son projenin son hali şu şekilde olacaktır;
Android'in official kütüphanesi olan SQLiteOpenHelper sınıfı miras alınarak yeni bir sınıf oluşturalım. Bu sınıf CRUD(Create, Read, Update, Delete) yani notlarımız için gerekli olan ekleme, okuma, güncelleme ve silme işlemlerini kapsayacak şekilde ayarlanacaktır.
Veritabanına kayıt edilen notları daha kolay yönetebilmek için Notes modelini oluşturalım.
5. database/model paketi altında, Note.java sınıfı oluşturun. Bu sınıf içerisinde tablo ismi, sütunlar, bu tabloya ait SQL sorgularını ve getter/setter metodlarını içermektir.
public class Note { public static final String TABLE_NAME = "notes"; public static final String COLUMN_ID = "id"; public static final String COLUMN_NOTE = "note"; public static final String COLUMN_TIMESTAMP = "timestamp"; private int id; private String note; private String timestamp; // Create table SQL query public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NOTE + " TEXT," + COLUMN_TIMESTAMP + " DATETIME DEFAULT CURRENT_TIMESTAMP" + ")"; public Note() { } public Note(int id, String note, String timestamp) { this.id = id; this.note = note; this.timestamp = timestamp; } public int getId() { return id; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public String getTimestamp() { return timestamp; } public void setId(int id) { this.id = id; } public void setTimestamp(String timestamp) { this.timestamp = timestamp; } }
6. database paketi altında, DatabaseHelper.java adında ve SQLiteOpenHelper sınıfını miras alan bir sınıf oluşturun. Bu sınıf veritabanı için yapılacak tüm işlemlerde kullanılacaktır.
import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.ArrayList; import java.util.List; import info.yazilimdersi.sqlite.database.model.Note; public class DatabaseHelper extends SQLiteOpenHelper { // Veritabanı versiyonu private static final int DATABASE_VERSION = 1; // Veritabanı adı private static final String DATABASE_NAME = "notes_db"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } // Tabloların oluşturulması @Override public void onCreate(SQLiteDatabase db) { // notes tablosunu oluştur db.execSQL(Note.CREATE_TABLE); } // Veritabanının güncellenmesi @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Mevcut notes tablosunu kaldır. db.execSQL("DROP TABLE IF EXISTS " + Note.TABLE_NAME); // Veritabanını tekrardan oluştur. onCreate(db); } }
Artık notları kayıt etmede kullanılacak olan veritabanı oluşturuldu. Şimdi aynı sınıfa aşağıdaki fonksiyonları ekleyelim;
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanına yeni bir notun nasıl kayıt edildiğini görebilirsiniz;
public long insertNote(String note) { // veritabanına erişimde kullanılacak nesne SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); // `id` and `timestamp` otomatik oluşturulduğu için eklemeye gerek yoktur. values.put(Note.COLUMN_NOTE, note); // yeni kayıt oluştur long id = db.insert(Note.TABLE_NAME, null, values); // bağlantıyı kapat db.close(); // yeni eklenen kaydın id bilgisini dönebilirsin. return id; }
Bu fonksiyon veritabanına okuma imkanı sunan getReadableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı olan tüm notların ve sadece istenilen nota erişimi görebilirsiniz;
public Note getNote(long id) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.query(Note.TABLE_NAME, new String[]{Note.COLUMN_ID, Note.COLUMN_NOTE, Note.COLUMN_TIMESTAMP}, Note.COLUMN_ID + "=?", new String[]{String.valueOf(id)}, null, null, null, null); if (cursor != null) cursor.moveToFirst(); Note note = new Note( cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID)), cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE)), cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP))); // veritabanı bağlantısını kapatalım cursor.close(); return note; } public ListgetAllNotes() { List notes = new ArrayList<>(); // Select Sorgusu String selectQuery = "SELECT * FROM " + Note.TABLE_NAME + " ORDER BY " + Note.COLUMN_TIMESTAMP + " DESC"; SQLiteDatabase db = this.getWritableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); if (cursor.moveToFirst()) { do { Note note = new Note(); note.setId(cursor.getInt(cursor.getColumnIndex(Note.COLUMN_ID))); note.setNote(cursor.getString(cursor.getColumnIndex(Note.COLUMN_NOTE))); note.setTimestamp(cursor.getString(cursor.getColumnIndex(Note.COLUMN_TIMESTAMP))); notes.add(note); } while (cursor.moveToNext()); } // veritabanı bağlantısını kapatalım db.close(); // notların tümünü döner return notes; } public int getNotesCount() { String countQuery = "SELECT * FROM " + Note.TABLE_NAME; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(countQuery, null); int count = cursor.getCount(); cursor.close(); // notların sayısını döner return count; }
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı bir notun nasıl güncellenebildiğini görebilirsiniz;
public int updateNote(Note note) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(Note.COLUMN_NOTE, note.getNote()); // notunu güncelleyelim return db.update(Note.TABLE_NAME, values, Note.COLUMN_ID + " = ?", new String[]{String.valueOf(note.getId())}); }
Bu fonksiyon veritabanına yazma imkanı sunan getWritableDatabase() metoduna erişim gerektirmektedir. Aşağıdaki kodlamada veritabanında kayıtlı bir notun nasıl silindiğini görebilirsiniz;
public void deleteNote(Note note) { SQLiteDatabase db = this.getWritableDatabase(); db.delete(Note.TABLE_NAME, Note.COLUMN_ID + " = ?", new String[]{String.valueOf(note.getId())}); db.close(); }
7. utils paketi altında, RecyclerTouchListener.java ve MyDividerItemDecoration.java adında sınıflar oluşturun.
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private ClickListener clicklistener; private GestureDetector gestureDetector; public RecyclerTouchListener(Context context, final RecyclerView recycleView, final ClickListener clicklistener) { this.clicklistener = clicklistener; gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onLongPress(MotionEvent e) { View child = recycleView.findChildViewUnder(e.getX(), e.getY()); if (child != null && clicklistener != null) { clicklistener.onLongClick(child, recycleView.getChildAdapterPosition(child)); } } }); } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { View child = rv.findChildViewUnder(e.getX(), e.getY()); if (child != null && clicklistener != null && gestureDetector.onTouchEvent(e)) { clicklistener.onClick(child, rv.getChildAdapterPosition(child)); } return false; } @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { } @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } public interface ClickListener { void onClick(View view, int position); void onLongClick(View view, int position); } }
import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.View; public class MyDividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; private Context context; private int margin; public MyDividerItemDecoration(Context context, int orientation, int margin) { this.context = context; this.margin = margin; final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left + dpToPx(margin), top, right - dpToPx(margin), bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top + dpToPx(margin), right, bottom - dpToPx(margin)); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } private int dpToPx(int dp) { Resources r = context.getResources(); return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics())); } }
Veritabanı ile alakalı işlemler gerçekleştirildi. Şimdi sıra uygulamanın arayüzünün oluşturulması ve bunun veritabanı ile ilişkilendirilmesinde;
Öncelikle notlarımız listelendiği bir layout sayfasına ve bununla ilişkili adapter sınıfına ihtiyacımız bulunmakta.
9. Her notun tek başına görüntülenebildiği arayüzü oluşturmak için note_list_row.xml adında bir layout oluşturun.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:paddingBottom="@dimen/dimen_10" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="@dimen/dimen_10"> <TextView android:id="@+id/dot" android:layout_width="wrap_content" android:layout_height="@dimen/dot_height" android:layout_marginRight="@dimen/dot_margin_right" android:layout_marginTop="@dimen/dimen_10" android:includeFontPadding="false" android:textColor="@color/colorAccent" android:lineSpacingExtra="0dp" android:textSize="@dimen/dot_text_size" /> <TextView android:id="@+id/timestamp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toRightOf="@id/dot" android:textColor="@color/timestamp" android:textSize="@dimen/timestamp" /> <TextView android:id="@+id/note" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/timestamp" android:layout_toRightOf="@id/dot" android:textColor="@color/note_list_text" android:textSize="@dimen/note_list_text" /> </RelativeLayout>
10. view paketi altında, NotesAdapter.java adında bir sınıf oluşturalım. Bu adapter arayüz ile alakalı yapılması planlanan gösterimlerde kullanılacaktır. Ayrıca listelemede tıklanan notun hangisi olduğunu belirlemeye de yaramaktadır.
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import info.androidhive.sqlite.R; import info.androidhive.sqlite.database.model.Note; public class NotesAdapter extends RecyclerView.Adapter{ private Context context; private List notesList; public class MyViewHolder extends RecyclerView.ViewHolder { public TextView note; public TextView dot; public TextView timestamp; public MyViewHolder(View view) { super(view); note = view.findViewById(R.id.note); dot = view.findViewById(R.id.dot); timestamp = view.findViewById(R.id.timestamp); } } public NotesAdapter(Context context, List notesList) { this.context = context; this.notesList = notesList; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.note_list_row, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { Note note = notesList.get(position); holder.note.setText(note.getNote()); // Her notun başında nokta simgesinin gösterimi holder.dot.setText(Html.fromHtml("•")); // Oluşturulduğu zaman diliminin formatlanması ve görüntülenmesi holder.timestamp.setText(formatDate(note.getTimestamp())); } @Override public int getItemCount() { return notesList.size(); } private String formatDate(String dateStr) { try { SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = fmt.parse(dateStr); SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d"); return fmtOut.format(date); } catch (ParseException e) { } return ""; } }
Oluşturulacak dialogda sadece not girilmesi veya notun editlenebilmesi gibi özellik içerdiğinden EditText elementinin layouta eklenmesi yeterli olacaktır. Burada daha hızlı aksiyon almak adına direkt olarak Dialog elementini kullanabiliriz.
10. Yeni not girmede kullanılacak olan note_dialog.xml adında bir layout oluşturun.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingLeft="@dimen/activity_margin" android:paddingRight="@dimen/activity_margin" android:paddingTop="@dimen/activity_margin"> <TextView android:id="@+id/dialog_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/dimen_10" android:fontFamily="sans-serif-medium" android:lineSpacingExtra="8sp" android:text="@string/lbl_new_note_title" android:textColor="@color/colorAccent" android:textSize="@dimen/lbl_new_note_title" android:textStyle="normal" /> <EditText android:id="@+id/note" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/transparent" android:gravity="top" android:hint="@string/hint_enter_note" android:inputType="textCapSentences|textMultiLine" android:lines="4" android:textColorHint="@color/hint_enter_note" android:textSize="@dimen/input_new_note" /> </LinearLayout>
11. activity_main.xml ve content_main.xml dosyalarını açın ve içerisine RecyclerView widgetini ekleyin.
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/coordinator_layout" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="info.androidhive.sqlite.view.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_main" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@drawable/ic_add_white_24dp" /> </android.support.design.widget.CoordinatorLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="info.androidhive.sqlite.view.MainActivity" tools:showIn="@layout/activity_main"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:id="@+id/empty_notes_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/margin_top_no_notes" android:fontFamily="sans-serif-light" android:text="@string/msg_no_notes" android:textColor="@color/msg_no_notes" android:textSize="@dimen/msg_no_notes" /> </RelativeLayout>
12. Son olarak MainActivity.java sınıfını açıp aşağıdaki düzenlemeleri yapın;
import android.content.DialogInterface; import android.os.Bundle; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import info.androidhive.sqlite.R; import info.androidhive.sqlite.database.DatabaseHelper; import info.androidhive.sqlite.database.model.Note; import info.androidhive.sqlite.utils.MyDividerItemDecoration; import info.androidhive.sqlite.utils.RecyclerTouchListener; public class MainActivity extends AppCompatActivity { private NotesAdapter mAdapter; private ListBöylelikle SQLite kullanarak Android uygulamada basit bir not uygulaması hazırlanmış oldu. ]]>notesList = new ArrayList<>(); private CoordinatorLayout coordinatorLayout; private RecyclerView recyclerView; private TextView noNotesView; private DatabaseHelper db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); coordinatorLayout = findViewById(R.id.coordinator_layout); recyclerView = findViewById(R.id.recycler_view); noNotesView = findViewById(R.id.empty_notes_view); db = new DatabaseHelper(this); notesList.addAll(db.getAllNotes()); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showNoteDialog(false, null, -1); } }); mAdapter = new NotesAdapter(this, notesList); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16)); recyclerView.setAdapter(mAdapter); toggleEmptyNotes(); recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, new RecyclerTouchListener.ClickListener() { @Override public void onClick(View view, final int position) { } @Override public void onLongClick(View view, int position) { showActionsDialog(position); } })); } private void createNote(String note) { // yeni not ekleyin long id = db.insertNote(note); // veritabanına eklenen yeni notun id bilgisini alın. Note n = db.getNote(id); if (n != null) { // listeye yeni not ekleyin notesList.add(0, n); // listelemeyi güncelleyin mAdapter.notifyDataSetChanged(); toggleEmptyNotes(); } } private void updateNote(String note, int position) { Note n = notesList.get(position); // notun text kısmını setleyin n.setNote(note); // notu veritabanında güncelleyin db.updateNote(n); // listeyi güncelleyin notesList.set(position, n); mAdapter.notifyItemChanged(position); toggleEmptyNotes(); } private void deleteNote(int position) { // veritabanından notu silin db.deleteNote(notesList.get(position)); // listeden notu kaldırın notesList.remove(position); mAdapter.notifyItemRemoved(position); toggleEmptyNotes(); } private void showActionsDialog(final int position) { CharSequence colors[] = new CharSequence[]{"Güncelle", "Sil"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Seçeneği seçin"); builder.setItems(colors, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0) { showNoteDialog(true, notesList.get(position), position); } else { deleteNote(position); } } }); builder.show(); } private void showNoteDialog(final boolean shouldUpdate, final Note note, final int position) { LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext()); View view = layoutInflaterAndroid.inflate(R.layout.note_dialog, null); AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(MainActivity.this); alertDialogBuilderUserInput.setView(view); final EditText inputNote = view.findViewById(R.id.note); TextView dialogTitle = view.findViewById(R.id.dialog_title); dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_note_title) : getString(R.string.lbl_edit_note_title)); if (shouldUpdate && note != null) { inputNote.setText(note.getNote()); } alertDialogBuilderUserInput .setCancelable(false) .setPositiveButton(shouldUpdate ? "güncelle" : "kaydet", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogBox, int id) { } }) .setNegativeButton("iptal", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogBox, int id) { dialogBox.cancel(); } }); final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); alertDialog.show(); alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Herhangi bir not girilmediğinde hata mesajının gösterilmesi if (TextUtils.isEmpty(inputNote.getText().toString())) { Toast.makeText(MainActivity.this, "Not Girin!", Toast.LENGTH_SHORT).show(); return; } else { alertDialog.dismiss(); } // eğer kullanıcı notlarda güncelleme yapıyorsa if (shouldUpdate && note != null) { // kayıtlı notu id verisi ile güncellemek updateNote(inputNote.getText().toString(), position); } else { // yeni not oluşturma createNote(inputNote.getText().toString()); } } }); } /** * Eğer kayıtlı not bulunmuyorsa layout değişikliğinin sağlanması */ private void toggleEmptyNotes() { if (db.getNotesCount() > 0) { noNotesView.setVisibility(View.GONE); } else { noNotesView.setVisibility(View.VISIBLE); } } }
#npm install ile react-native-cli modülünün kurulması npm install -g react-native-cli #react_ilk_uygulama isimli React Native uygulaması oluşturulması react-native init react_ilk_uygulamaYukarıdaki komutu çalıştırmanız ile birlikte react_ilk_uygulama isimli dizinde React Native projesi oluşturulur. Oluşturulan dizin yapısı şu şekilde olacaktır;
export default class App extends Component<{}> { render() { return ( <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started, edit App.js </Text> <Text style={styles.instructions}> {instructions} </Text> </View> ); } }Dosyada gördüğünüz üzere uygulamanın ilk sayfasında Welcome to React Native texti görüntülenecek şekilde bir kodlama gerçekleştirilmiştir. Projenin çalıştırılması için aşağıdaki komutları çalıştırmanız gerekmektedir.
#android uygulamayı derlemek için kullanılan kod react-native run-android #ios uygulamayı derlemek için kullanılan kod react-native run-iosProjenin Android uygulama olarak derlenmesi için ANDROID_HOME değişkeninin ortam değişkeni olarak bilgisayarınıza eklemesi gerekmektedir. Bunun için öncelikle Android SDK'yini linkten indirmeniz gerekmektedir. Sonrasında aşağıda tanımlı olan komut ile ortam değişkeninize ANDROID_HOME değişkenini tanımlayabilirsiniz.
#Windows için set ANDROID_HOME=C:\<installation location>\android-sdk-windows set PATH=%PATH%;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools
#Mac OS X için export ANDROID_HOME=/<installation location>/android-sdk-macosx export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-toolsKomutun çalışması ile birlikte emülatörde yazılı olan mesajı gözlemleyebilirsiniz.
export default class App extends Component<{}> { render() { return ( <View style={styles.container}> <Text style={styles.welcome}> React Native projeme hoşgeldiniz! </Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#FF0000' }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, color: '#CCCCCC' } });
#npm init ile package.json dosyası yoksa oluşturulması npm init #npm ile create-react-app modülünün yüklenmesi npm install -g create-react-app #create-react-app ile yeni uygulama oluşturulması create-react-app ornek-pwa-uygulamasiYukarıdaki komutun çalıştırılması ile birlikte aşağıdaki şekilde bir ekran görüntüsü oluşacaktır.
cd ornek-pwa-uygulamasi #react-router modulunun kurulması npm install --save [email protected]Daha sonra hazırlanan proje kodunda src dizini içine girilerek App.js dosyasının aşağıdaki kodlara göre güncellenmesi gerekmektedir.
#src dizini içerisine girin. cd src #App.js dosyası içerisine asagıdaki kodu yapıştırın. import React, { Component } from 'react'; import { Router, browserHistory, Route, Link } from 'react-router'; import logo from './logo.svg'; import './App.css'; const Page = ({ title }) => ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h2>{title}</h2> </div> <p className="App-intro"> Bu {title} sayfasıdır. </p> <p> <Link to="/">Anasayfa</Link> </p> <p> <Link to="/hakkinda">Hakkında</Link> </p> <p> <Link to="/ayarlar">Ayarlar</Link> </p> </div> ); const Anasayfa = (props) => ( <Page title="Anasayfa"/> ); const Hakkinda = (props) => ( <Page title="Hakkinda"/> ); const Ayarlar = (props) => ( <Page title="Ayarlar"/> ); class App extends Component { render() { return ( <Router history={browserHistory}> <Route path="/" component={Anasayfa}/> <Route path="/hakkinda" component={Hakkinda}/> <Route path="/ayarlar" component={Ayarlar}/> </Router> ); } } export default App;Son olarak npm start komutunu çalıştırarak projenin 3000 portu üzerinden çalışmasını sağlayabilirsiniz.
#projenin çalıştırılması npm start2. Lighthouse Chrome Plugin Kurulumu:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <title>React Uygulaması</title> </head> <body> <div id="root"></div> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('service-worker.js').then(function(registration) { console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { console.log('ServiceWorker registration failed: ', err); }).catch(function(err) { console.log(err) }); }); } else { console.log('service worker is not supported'); } </script> </body> </html>Son olarak cache mekanizmasının hazırlanması kaldı. Aşağıdaki kod parçacığını daha önceden oluşturduğumuz service.workers.js dosyası içerisine yapıştıralım.
var doCache = false; var CACHE_NAME = 'my-pwa-cache-v1'; self.addEventListener("activate", event => { const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(keyList => Promise.all(keyList.map(key => { if (!cacheWhitelist.includes(key)) { console.log('Deleting cache: ' + key) return caches.delete(key); } })) ) ); }); self.addEventListener('install', function(event) { if (doCache) { event.waitUntil( caches.open(CACHE_NAME) .then( function(cache) { fetch("asset-manifest.json") .then(response => { response.json() }) .then(assets => { const urlsToCache = [ "/", assets["main.js"] ] cache.addAll(urlsToCache) console.log('cached'); }) }) ); } }); self.addEventListener('fetch', function(event) { if (doCache) { event.respondWith( caches.match(event.request).then( function(response) { return response || fetch(event.request); }) ); } });Şimdi tekrardan Lighthouse pluginini çalıştırıp generate report ile son durumu gözlemleyelim.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <title>React Uygulaması</title> <!-- Add in some basic styles for our HTML --> <style type="text/css"> body { margin: 0; padding: 0; font-family: sans-serif; } .App { text-align: center; } .App-header { background-color: #222; height: 150px; padding: 20px; color: white; } .App-intro { font-size: large; } </style> </head> <body> <!-- Filler HTML as our app starts up --> <div id="root"> <div class="App"> <div class="App-header"> <h2>Home</h2> </div> <p class="App-intro"> Site yükleniyor.. </p> </div> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('service-worker.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }).catch(function(err) { console.log(err) }); }); } else { console.log('service worker is not supported'); } </script> </body> </html>5. Siteye mobil uygulama özelliği kazandırılması:
{ "short_name": "İlk PWA Uygulamam", "name": "İlk Progressive Web Uygulamam", "icons": [ { "src":"icon.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=homescreen", "background_color": "#222", "theme_color": "#222", "display": "standalone" }icon.png dosyasının boyutu 192x192 şeklinde olmalıdır.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <!-- manifest dosyasını tanımla --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <!-- Browsera PWA uyumlu olduğunu söyle --> <meta name="mobile-web-app-capable" content="yes"> <!-- iOS'a PWA uyumlu olduğunu söyle --> <meta name="apple-mobile-web-app-capable" content="yes"> <!-- Tema renginin tanımlı olduğundan emin ol --> <meta name="theme-color" content="#536878"> <title>React Uygulaması</title>6. Firebase Üzerinde Uygulamanın Çalıştırılması:
#firebase-tools indirilmesi npm install -g firebase-tools #firebase modülüne giriş firebase login #firebase tabanlı proje oluşturulması firebase init #firebasede projenin canlıya atılması npm run build && firebase deploy]]>
Öncelikle aşağıda bulunan komut satırını terminalde çağırarak Ubuntu repository'sinize mc3man ppa kütüphanesini ekleyin.
sudo add-apt-repository ppa:mc3man/trusty-media
Bu komutu Enter'e basarak çalıştırdığınızda, terminalde aşağıdaki ifadeyi görmeniz gerekmektedir;
Also note that with apt-get a sudo apt-get dist-upgrade is needed for initial setup & with some package upgrades More info: https://launchpad.net/~mc3man/+archive/ubuntu/trusty-media Press [ENTER] to continue or ctrl-c to cancel adding it
Şimdi Ubuntu paketlerini aşağıdaki komutla güncelleyin.
sudo apt-get update sudo apt-get dist-upgrade
Şu an Ubuntu 14.04 işletim sisteminiz FFmpeg kurulumuna uygun hale getirilmiştir. Aşağıdaki komutu çalıştırarak FFmpeg kurulumunu sorunsuz şekilde yerine getirebilirsiniz.
sudo apt-get install ffmpeg]]>
package com.yazilimdersi.info.finalkullanimi; public class Urun{ #urunadi final değişken olarak setlendi. private final String urunadi; public void urunAdiYazdir() { System.out.println("urunadi : "+urunadi); } }
package com.yazilimdersi.info.finalkullanimi; public class Urun{ #urunadi final değişken olarak setlendi. private final String urunadi; public void urunAdiYazdir() { urunadi = "FLOWMETRE"; System.out.println("urunadi : "+urunadi); } }
package com.yazilimdersi.info.finalkullanimi; public class Urun{ #urunadi final değişken olarak setlendi. private final String urunadi = "FLOWMETRE"; public void urunAdiYazdir() { System.out.println("urunadi : "+urunadi); } }
package com.yazilimdersi.info.finalkullanimi; public class Urun{ #urunadi final değişken olarak setlendi. private final String urunadi; public Urun(String urunAdiDegiskeni) { urunadi = urunAdiDegiskeni; } public void urunAdiYazdir() { System.out.println("urunadi : "+urunadi); } }
package com.yazilimdersi.info.finalkullanimi; public class Urun{ #urunadi final değişken olarak setlendi. private final String urunadi; public Urun(String urunAdiDegiskeni) { urunadi = urunAdiDegiskeni; } public void urunAdiYazdir() { urunadi = "FLOWMETRE"; System.out.println("urunadi : "+urunadi); } }
package com.yazilimdersi.info.finalkullanimi; public class Constant{ public static final String MYSQL_HOST = "128.93.09.12"; public static final String MYSQL_USER = "mysql_user"; public static final String MYSQL_PASS = "password"; }
package com.yazilimdersi.info.statickullanimi; public class Urun{ #urunsayisi Sınıf değişkeni. Program çalışır çalışmaz bellekte yer oluşturulur. public static int urunsayisi = 0; public final int urunsayisiGetir() { return urunsayisi; } } public class Arac extends Urun { public int urunsayisiGetir(){ System.out.println("urunsayisi getir"); } }
package com.yazilimdersi.info.statickullanimi; public final class Urun { #urunsayisi Sınıf değişkeni. Program çalışır çalışmaz bellekte yer oluşturulur. public static int urunsayisi = 0; public int urunsayisiGetir() { return urunsayisi; } } public class Arac extends Urun { public int urunsayisiGetir(){ System.out.println("urunsayisi getir"); } }
package com.yazilimdersi.info.thiskullanimi; public class Urun{ private String urunadi; private String marka; private String model; public Urun(String urunadi, String marka, String model) { this.urunadi= urunadi; this.marka = marka; this.model = model; } }
package com.yazilimdersi.info.thiskullanimi; public class Urun{ private String urunadi; private String marka; private String model; public Urun(String urunadiDegiskeni, String markaDegiskeni, String modelDegiskeni) { urunadi= urunadiDegiskeni; marka = markaDegiskeni; model = modelDegiskeni; } }
package com.yazilimdersi.info.thiskullanimi; public class Urun{ private String urunadi; private String marka; private String model; public Urun(String urunAdi) { this(urunAdi, "FLOWMETRE", "FL 256"); } public Urun(String urunadi, String marka, String model) { this.urunadi= urunadi; this.marka = marka; this.model = model; } }
sudo touch app.js
#app.js dosyasının içerisine girildi. vi app.js #http modülü oluşturuldu. var http = require("http"); http.createServer(function(req, res){ }).listen(, '127.0.0.1');
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<!doctype html>\n<html lang="en">\n' + '\n<meta charset="utf-8">\n<title>Node.js ile basit bir sayfa</title>\n' + '<style type="text/css">* {font-family:arial, sans-serif;}</style>\n' + '\n\n<h1>En popüler programlama dilleri</h1>\n' + '<div id="content"><p>Son 3 yıla ait en popüler programlama dilleri:</p>\n'+ '<ul><li>Java</li><li>C#</li><li>Ruby</li><li>Nodejs</li></ul></div>' + '\n\n');
res.end()
var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.write('<!doctype html>\n<html lang="en">\n' + '\n<meta charset="utf-8">\n<title>Node.js ile basit bir sayfa</title>\n' + '<style type="text/css">* {font-family:arial, sans-serif;}</style>\n' + '\n\n<h1>En popüler programlama dilleri</h1>\n' + '<div id="content"><p>Son 3 yıla ait en popüler programlama dilleri</p>\n' + '<ul><li>Java</li><li>C#</li><li>Ruby</li><li>Nodejs</li></ul></div>' + '\n\n'); res.end(); }).listen(1111, '127.0.0.1');
node app.js
package com.yazilimdersi.info.statickullanimi; public class Urun{ private String urunadi; private String marka; private String model; private int fiyat; #urunsayisi Sınıf değişkeni. Program çalışır çalışmaz bellekte yer oluşturulur. public static int urunsayisi = 0; public Urun(String urunadi, String marka, String model, int fiyat) { this.urunadi= urunadi; this.marka = marka; this.model = model; this.fiyat = fiyat; #Urun sınıfına ait her nesne oluşturulduğunda urunsayisini bir artıralım. urunsayisi++; } }
package com.yazilimdersi.info.statickullanimi; public class StaticOrnekProgram { public static void main(String args[]) { System.out.println("ürün sayısı: " + Urun.urunsayisi); #üc tane urun nesnesi olusturalım. Urun urun1 = new Urun("Pals Oximeter", "Erne", "UT 100", 1200); Urun urun2 = new Urun("Ateşölçer", "Thermoflash", "LX-26", 1000); Urun urun3 = new Urun("FLOWMETRE", "Özen", "Perfect Aneroid", 240); int urunsayisi = Urun.urunsayisi; System.out.println("Nesnelerden sonra ürün sayısı: " + urunsayisi); urunsayisi1 = urun1.urunsayisi; System.out.println("İlk nesnede ürün sayısı: " + urunsayisi1); urunsayisi2 = urun2.urunsayisi; System.out.println("İkinci nesnede ürün sayısı: " + urunsayisi2); urunsayisi3 = urun3.urunsayisi; System.out.println("Üçüncü nesnede ürün sayısı: " + urunsayisi3); } }
ürün sayısı: 0 Nesnelerden sonra ürün sayısı: 3 İlk nesnede ürün sayısı: 3 İkinci nesnede ürün sayısı: 3 Üçüncü nesnede ürün sayısı: 3
package com.yazilimdersi.info.statickullanimi; public class Urun{ private String urunadi; private String marka; private String model; private int fiyat; #urunsayisi Sınıf değişkeni. Program çalışır çalışmaz bellekte yer oluşturulur. public static int urunsayisi = 0; public Urun(String urunadi, String marka, String model, int fiyat) { this.urunadi= urunadi; this.marka = marka; this.model = model; this.fiyat = fiyat; #Urun sınıfına ait her nesne oluşturulduğunda urunsayisini bir artıralım. urunsayisi++; } public static int urunsayisiGetir() { return urunsayisi; } }
package com.yazilimdersi.info.statickullanimi; public class StaticOrnekProgram { public static void main(String args[]) { System.out.println("ürün sayısı: " + Urun.urunsayisi); #üc tane urun nesnesi olusturalım. Urun urun1 = new Urun("Pals Oximeter", "Erne", "UT 100", 1200); Urun urun2 = new Urun("Ateşölçer", "Thermoflash", "LX-26", 1000); Urun urun3 = new Urun("FLOWMETRE", "Özen", "Perfect Aneroid", 240); int urunsayisi = Urun.urunsayisiGetir(); System.out.println("Nesnelerden sonra ürün sayısı: " + urunsayisi); } }
ürün sayısı: 0 Nesnelerden sonra ürün sayısı: 3
package com.yazilimdersi.info.statickullanimi; import static java.lang.Math.*; public class OrnekProgram { public static void main(String args[]) { System.out.println("Cosinus 90: " + cos(90)); System.out.println("Pi sayısı: " + PI); } }
sudo apt-get update sudo apt-get install nodejs
sudo apt-get install npm
curl -sL https://deb.nodesource.com/setup | sudo bash -
sudo apt-get install nodejs
sudo apt-get install build-essential
# http clienti oluşturuldu. HttpClient httpClient = new DefaultHttpClient(); # http post oluşturuldu. HttpPost httpPost = new HttpPost("http://yazilimdersi.info/urunlerlistesi");
# ulke ve sehir parametreleri setlenmektedir. List<NameValuePair> ulkeSehirParametreleri = new ArrayList<NameValuePair>(2); ulkeSehirParametreleri.add(new BasicNameValuePair("ulke", "Turkiye")); ulkeSehirParametreleri.add(new BasicNameValuePair("sehir", "Ankara"));
# post parametrelerinin urlencode edilmesi try { httpPost.setEntity(new UrlEncodedFormEntity(ulkeSehirParametreleri)); } catch (UnsupportedEncodingException e) { # hataların loglara yazılması e.printStackTrace(); }
# http isteğinin yapılması try { HttpResponse response = httpClient.execute(httpPost); # dönen sonuçların görüntülenmesi Log.d("Http Response:", response.toString()); } catch (ClientProtocolException e) { # hataların loglara yazılması e.printStackTrace(); } catch (IOException e) { # hataların loglara yazılması e.printStackTrace(); }Yukarıda yazılan kodlama ile birlikte http isteği gerçekleştirilmiştir. Aşağıda bu kodların tümünün görüntülendiği sınıfa ait kodlama bulunmaktadır:
package com.androidhive.httprequests; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class AndroidHTTPIstegiActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); # http isteği oluşturuldu. HttpClient httpClient = new DefaultHttpClient(); # http post isteği oluşturuldu. HttpPost httpPost = new HttpPost("http://yazilimdersi.info/urunlerlistesi"); # parametrelerin setlenmesi List<NameValuePair> ulkeSehirParametreleri = new ArrayList<NameValuePair>(2); ulkeSehirParametreleri.add(new BasicNameValuePair("ulke", "Turkiye")); ulkeSehirParametreleri.add(new BasicNameValuePair("sehir", "Ankara")); # post parametrelerinin urlencode edilmesi try { httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair)); } catch (UnsupportedEncodingException e) { # hataların loglara yazılması e.printStackTrace(); } # http isteğinin gerçekleştirilmesi try { HttpResponse response = httpClient.execute(httpPost); # hataların loglara yazılması Log.d("Http Response:", response.toString()); } catch (ClientProtocolException e) { # hataların loglara yazılması e.printStackTrace(); } catch (IOException e) { # hataların loglara yazılması e.printStackTrace(); } } }
sudo nano /etc/apache2/httpd.conf
# Virtual hostlar Include /private/etc/apache2/extra/httpd-vhosts.conf
sudo nano /etc/apache2/extra/httpd-vhosts.conf
<VirtualHost *:80> ServerName yazilimdersi.info ServerAlias www.yazilimdersi.info DocumentRoot "/Users/yazilim/Sites/yazilimdersi" ErrorLog "/private/var/log/apache2/apple.com-error_log" CustomLog "/private/var/log/apache2/apple.com-access_log" common ServerAdmin [email protected] <Directory "/Users/yazilim/Sites/yazilimderi"> Options Indexes FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>
sudo nano /etc/hosts
127.0.0.1 yazilimdersi.info www.yazilimdersi.info
sudo apachectl restart
sudo apt-get update
sudo apt-get install tomcat7
http://makinaniza-ait-ip-adresi:8080
sudo apt-get install tomcat7-docs tomcat7-admin tomcat7-examples
sudo apt-get install default-jdk
sudo nano /etc/tomcat7/tomcat-users.xml
<tomcat-users> <user username="kullanıcı adı" password="şifre" roles="manager-gui,admin-gui"/> </tomcat-users>
sudo service tomcat7 restart
http://makinanizin-ip-adresi:8080
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor
brew options ffmpeg #komut çıktısı --with-fdk-aac Enable the Fraunhofer FDK AAC library --with-ffplay Enable FFplay media player --with-freetype Build with freetype support
#bazı ayarlar yazılarak yapılan ffmpeg kurulumu için; brew install ffmpeg --with-fdk-aac --with-ffplay --with-freetype --with-frei0r --with-libass --with-libvo-aacenc --with-libvorbis --with-libvpx --with-opencore-amr --with-openjpeg --with-opus --with-rtmpdump --with-schroedinger --with-speex --with-theora --with-tools #default ayarlara göre ffmpeg kurulumu için; brew install ffmpeg
<?php function gercekIPAdresiniGetir() { if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip=$_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$_SERVER['HTTP_X_FORWARDED_FOR']; } else { $ip=$_SERVER['REMOTE_ADDR']; } return $ip; } ?>
sudo apt-get update
sudo apt-get install mysql-server php5-mysql php5 php5-memcache
sudo apt-get install memcached
sudo apt-get install php-pear
sudo apt-get install build-essential
sudo pecl install memcache
echo "extension=memcache.so" | sudo tee /etc/php5/conf.d/memcache.ini
ps aux | grep memcache
echo "stats settings" | nc localhost 11211
function kitapisminigetir(kitap_id) #kitap isminin memcachede kayıtlı olup olmadığını kontrol edelim. kitapismi = memcached_get("kitapismi:" . kitap_id) return kitapismi if defined kitapismi #veritabanından kitap ismini getirelim. kitapismi = veritabanindangetir(kitap_id) #veritabanından getirilen kitapismini memcache kayıt edelim. memcached_set("kitapismi:" . kitap_id, kitapismi) return kitapismi end
mysql -u root -p use test; grant all on test.* to testkullanici@localhost identified by 'testsifre'; create table ornek (id int, ad varchar(30)); insert into ornek values (1, "ornekveri1"); insert into ornek values (2, "ornekveri2"); insert into ornek values (3, "ornekveri3"); exit;
nano memcachetest.php
<?php $memcachebaglanti = new Memcache(); $memcachebaglanti->pconnect('localhost', 11211);
mysql_connect("localhost", "testkullanici", "testsifre") or die(mysql_error()); mysql_select_db("test") or die(mysql_error());
$sorgu = "select id from ornek where ad= 'ornekveri1'"; $sorguAnahtari = "ANAHTARKELIME :" . md5($sorgu);
$sonuc = $memcachebaglanti->get($sorguAnahtari); if (!$sonuc) { $sonuc = mysql_fetch_array(mysql_query("select id from ornek where ad = 'ornekveri1'")) or die('mysql error'); $memcachebaglanti->set($sorguAnahtari, $sonuc, 0, 300); print "sonuc veritabanından getirildi\n"; return $sonuc; } print "sonuc memcacheden getirildi\n"; return $sonuc; ?>
<?php $memcachebaglanti = new Memcache(); $memcachebaglanti->pconnect('localhost', 11211); mysql_connect("localhost", "testkullanici", "testsifre") or die(mysql_error()); mysql_select_db("test") or die(mysql_error()); $sorgu = "select id from ornek where ad= 'ornekveri1'"; $sorguAnahtari = "ANAHTARKELIME: " . md5($sorgu); $sonuc = $memcachebaglanti->get($sorguAnahtari); if (!$sonuc) { $sonuc = mysql_fetch_array(mysql_query("select id from ornek where ad= 'ornekveri1'")) or die('mysql error'); $memcachebaglanti->set($sorguAnahtari, $sonuc, 0, 300); print "sonuc veritabanından getirildi\n"; return $sonuc; } print "sonuc memcacheden getirildi\n"; return $sonuc; ?>
# php memcachetest.php sonuc veritabanından getirildi # php memcachetest.php sonuc memcacheden getirildi # php memcachetest.php sonuc memcacheden getirildi. # php memcachetest.php << 5 dakika sonraki sorguda tekrar veritabanından getirilecektir. sonuc veritabanından getirildi. # php memcachetest.php sonuc memcachden getirildi.
Collections.sort(arraylist, Collections.reverseOrder()); #veya Collections.reverse(arraylist); Collections.sort(arraylist);
import java.util.*; public class ArrayListTersSiralama { public static void main(String args[]){ ArrayList<String> diller = new ArrayList<String>(); #diller arraylistine örnek programlama dilleri ekleyelim. diller.add("Java"); diller.add("Android"); diller.add("Php"); diller.add("Ruby On Rails"); diller.add("Linux"); #sıralanmamış arraylisti listeleyelim. System.out.println("Sıralanmamış Diller:"); for(String dil: diler){ System.out.println(dil); } #sıralamayı ters olarak gerçekleştirelim. Collections.sort(diller, Collections.reverseOrder()); #sıralanmış arraylisti listeleyelim. System.out.println("Ters Sıralanmış Diller:"); for(String dil: diller){ System.out.println(dil); } } }
Sıralanmamış Diller: Java Android Php Ruby On Rails Linux Ters Sıralanmış Diller: Ruby On Rails Php Linux Java Android
Collections.sort(arraylist);
import java.util.*; public class ArrayListSiralama { public static void main(String args[]){ ArrayList<String> diller = new ArrayList<String>(); #diller arraylistine örnek programlama dilleri ekleyelim. diller.add("Java"); diller.add("Android"); diller.add("Php"); diller.add("Ruby On Rails"); diller.add("Linux"); #sıralanmamış arraylisti listeleyelim. System.out.println("Sıralanmamış Diller:"); for(String dil: diler){ System.out.println(dil); } #sıralamayı gerçekleştirelim. Collections.sort(diller); #sıralanmış arraylisti listeleyelim. System.out.println("Sıralanmış Diller:"); for(String dil: diller){ System.out.println(dil); } } }
Sıralanmamış Diller: Java Android Php Ruby On Rails Linux Sıralanmış Diller: Android Java Linux Php Ruby On Rails
import java.util.*; public class ArrayListIntegerSiralama { public static void main(String args[]){ ArrayList<String> sayilar = new ArrayList<String>(); #sayilar arraylistine örnek sayılar ekleyelim. sayilar.add(134); sayilar.add(6); sayilar.add(19); sayilar.add(200); sayilar.add(120); sayilar.add(2); #sıralanmamış arraylisti listeleyelim. System.out.println("Sıralanmamış Sayılar:"); for(String sayi: sayilar){ System.out.println(sayi); } #sıralamayı gerçekleştirelim. Collections.sort(sayilar); #sıralanmış arraylisti listeleyelim. System.out.println("Sıralanmış Sayılar:"); for(String sayi: sayilar){ System.out.println(sayi); } } }
Sıralanmamış Sayılar: 134 6 19 200 120 2 Sıralanmış Sayılar: 2 6 19 120 134 200
import java.util.*;
ArrayList diller = new ArrayList();
ArrayList<Integer> diller = new ArrayList<Integer>();
import java.util.*; public class TekBoyut { public static void main(String[] args) { #konsoldan kullanıcının dinamik olarak program dili girmesini sağlayalım. Scanner tara=new Scanner(System.in); #diller adında arraylist tanımlayalım. ArrayList diller=new ArrayList(); for(int i=0;i<3;i++) { System.out.println("Programlama Dili Giriniz ("+(i+1)+") : "); #klavyeden girdiginiz programlama dillerini arrayliste ekliyoruz. diller.add(tara.next()); } for(int i=0;i<3;i++) { #eklenen dilleri listeleyelim. System.out.println(i+1+". dil:"+diller.get(i)); } #kayıtlı dillerin sayısı System.out.println("kayıtlı dil sayısı:"+diller.size()); #diller arraylistine statik olarak Java dilini ekleyelim. diller.add("Java") #kayıtlı dillerin sayısı System.out.println("'java' ekli kayıtlı dil sayısı:"+diller.size()); #diller arraylistindeki 2. elemanı silelim. diller.remove(1); System.out.println("2. eleman silindi" ); for(int i=0;i<diller.size();i++) { #diller arraylistinin son halini listeleyelim. System.out.println(i+1+". dil:"+diller.get(i)); } #dillerin tümü silindi diller.clear(); System.out.println("tüm diller silindi."); System.out.println("kayıtlı dil sayısı: "+diller.size()); } }
Programlama Dili Giriniz (1) : << Ruby on Rails Programlama Dili Giriniz (2) : << Android Programlama Dili Giriniz (3) : << C# Programlama Dili Giriniz (4) : << PHP 1. dil: Ruby on Rails 2. dil: Android 3. dil: C# 4. dil: PHP kayıtlı dil sayısı: 4 'java' ekli kayıtlı dil sayısı: 5 2. eleman silindi. 1. dil: Ruby on Rails 2. dil: C# 3. dil: PHP 4. dil: Java tüm diller silindi. kayıtlı dil sayısı: 0
<dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.12.4</version> </dependency>
MongoClient mongoClient = new MongoClient("localhost", 27017); DB database = mongoClient.getDB("yazilimdersi_db");
MongoCredential credential = MongoCredential.createCredential("kullanıcıadı", "mongodb", "şifre".toCharArray()); MongoClient mongoClient = new MongoClient(new ServerAddress("localhost"), Arrays.asList(credential)); DB database = mongoClient.getDB("yazilimdersi_db");
#ulkeler isimli collectiona bağlantı gerçekleştirelim. DBCollection col = database.getCollection("ulkeler"); #bu collectiona örnek kayıt atalım. BasicDBObject obj = new BasicDBObject() .append("id", 1) .append("ulke", "Brezilya") .append("ulkenufusu", 1000000); WriteResult result = col.insert(obj, WriteConcern.JOURNAL_SAFE);
#kayıtlı ulke sayısını yazalım. System.out.println("kayıtlı ulke sayısı : ".$col->count());
import com.mongodb.MongoClient; import com.mongodb.DBCollection; import com.mongodb.DB; import com.mongodb.BasicDBObject; import com.mongodb.DBCursor; import java.net.UnknownHostException; public class MongoDBClass { public static void main(String[] args) { try { MongoClient mongo = new MongoClient("localhost"); DB db = mongo.getDB("yazilimdersi_db"); DBCollection dbcol = db.getCollection("ulkeler"); DBCursor result = dbcol.find(); while (result.hasNext()) { System.out.println(result.next()); } } catch(UnknownHostException e) { System.out.println("Sunucu Hatası!"); } } }
import com.mongodb.MongoClient; import com.mongodb.DBCollection; import com.mongodb.DB; import com.mongodb.BasicDBObject; import com.mongodb.DBCursor; import java.net.UnknownHostException; public class MongoDBClass { public static void main(String[] args) { try { MongoClient mongo = new MongoClient("localhost"); DB db = mongo.getDB("yazilimdersi_db"); DBCollection dbcol = db.getCollection("ulkeler"); DBCursor result = dbcol.find("{ulkenufusu: 1000}"); while (result.hasNext()) { System.out.println(result.next()); } } catch(UnknownHostException e) { System.out.println("Sunucu Hatası!"); } } }
{ "_id" : { "$oid" : "4fc68190a09ef7490a0b3b40"} , "ulke" : "Brezilya" , "ulkenufusu" : "100000"}
import com.mongodb.MongoClient; import com.mongodb.DBCollection; import com.mongodb.DB; import com.mongodb.BasicDBObject; import com.mongodb.WriteResult; import java.net.UnknownHostException; import java.util.Date; public class MongoDBClass { public static void main(String[] args) { Date date = new Date(); try { MongoClient mongo = new MongoClient("localhost"); DB db = mongo.getDB("ornekdb"); DBCollection dbcol = db.getCollection("kullanicilar"); BasicDBObject obj = new BasicDBObject() .append("id", "1") .append("kullanici", "test user") .append("sifre", "1q2w3e") .append("date", date.getTime()); WriteResult result = dbcol.insert(obj, WriteConcern.JOURNAL_SAFE); System.out.println(result); } catch(UnknownHostException e) { System.out.println("Sunucu Hatası!"); } } }
import com.mongodb.MongoClient; import com.mongodb.DBCollection; import com.mongodb.DB; import com.mongodb.BasicDBObject; import com.mongodb.WriteResult; import java.net.UnknownHostException; import java.util.Date; public class MongoDBClass { public static void main(String[] args) { Date date = new Date(); try { MongoClient mongo = new MongoClient("localhost"); DB db = mongo.getDB("ornekdb"); DBCollection dbcol = db.getCollection("kullanicilar"); BasicDBObject obj = new BasicDBObject() .append("id", "1") .append("kullanici", "test user2") .append("sifre", "1q2w3e") .append("date", date.getTime()); WriteResult result = _dbcol.update( new BasicDBObject("kullanici", "test user"), new BasicDBObject("$set", obj) ); if (result.getLastError().ok()) { System.out.println("Güncelleme başarılı"); } else { System.out.println("Hata mesajı : " + result.getLastError().getErrorMessage()); } } catch(UnknownHostException e) { System.out.println("Sunucu Hatası!"); } } }
BasicDBObject document = new BasicDBObject(); document.put("number", 2); collection.remove(document);
#silinecek collectionun belirleyelim. collection.drop();
#veritabanı silinecektir. db.dropDatabase();
ALTER TABLE {TABLOISMI} AUTO_INCREMENT = 1;Not: Tabloda bulunan kayıtın değerinin altını veya aynısını setleyemezsiniz. Yani tablonuzda 4 idli herhangi bir veri varsa, ve yukarıda bulunan komutu 4 olarak setleyerek çalıştırmak isterseniz, hata ile karşılaşacaksınızdır. MyISAM yapısı kullanılan tablolarda eger yukarıdaki belirtilen sekilde bir yanlıs kayıt setlenmek istenirse, sistem otomatik olarak en yüksek olan kayıt +1 olarak setlemeyi gerçekleştirecektir. InnoDB yapısındaki tablolarda ise komut calısmayacaktır.
TRUNCATE TABLE {TABLOISMI};
DROP TABLE {TABLOISMI}; CREATE TABLE {TABLOISMI} { ... };
free -mYazılan komut sonrasında terminalde listelenecek içerik örnek olarak şu şekilde olacaktır.
total used free shared buffers cached
Mem: 7997 2618 5378 0 126 1353
-/+ buffers/cache: 1139 6858
Swap: 15623 0 15623
Ayrıca /proc/meminfo dosya içeriğinden cihanıza ait RAM ile alakalı bazı bilgiler alabilirsiniz. Aşağıda yazılı olan komutu kullanmanız yeterli olacaktır:
grep MemTotal /proc/meminfoYukarıda bulunan metod /proc/meminfo dosyasında MemTotal kelimesini aratmaktadır. Sonrasında bu satırı terminalde aşağıdaki şekilde görüntülemektedir:
MemTotal: 8121112 kBYukarıda bulunan metod /proc/meminfo dosyasında MemTotal kelimesini aratmaktadır. Sonrasında bu satırı terminalde aşağıdaki şekilde görüntülemektedir. Gördüğünüz üzere yukarıda bulunan çıktıda cihazımızın 8GB kapasiteye sahip bir RAM belleği bulunmaktadır.
cat /proc/cpuinfo | grep processor | wc -l #makinamdaki islemci sayısını listeler. 4Yukarıda bulunan komutla yapılan işlem aslında şu şekildedir. /proc/cpuinfo icerisinde bulunan dataları pipe yöntemi ile grep komutuna aktarmakta. Sonrasında içerisinde "processor" geçen kelimeleri getirmekte. En solda bulunan wc -l komutu ile de gelen kelimelerin miktarı hesasplanmaktadır.
#Kodlamayı git hesabından indirelim. git clone https://github.com/mongodb/mongo-php-driver #sürücünün derlenebilmesi için php-dev yükleyelim. sudo apt-get install php5-dev #kodlamanın bulunduğu dizin içerisine girelim. cd mongo-php-driver #Kodu derleyip yükleme işlemini gerçekleştirelim. phpize ./configure make sudo make install #Son olarak Php eklentisini aktif hale getirelim. sudo echo "extension=mongo.so" > /etc/php5/conf.d/10-mongo.ini
<?php try { // Mongo Sunucusuna bağlanalım $mongo = new Mongo('mongodb://localhost:27017'); // Veritabanını Seçelim $db = $mongo->selectDB('YazilimDersiDb'); } catch(MongoConnectionException $e) { die('Bağlantı kurulumunda sorun ile karşılaşıldı: ' . $e->getMessage()); } ?>
$mongo = new Mongo('mongodb://kullanıcıadı:şifre@localhost:27017');
<?php #diller isimli collectiona bağlantı gerçekleştirelim. $diller = new MongoCollection($db, 'diller'); #bu collectiona örnek kayıt atalım. $diller->insert(array('dil' => 'Android', 'makalesayisi' => 12)); $diller->insert(array('dil' => 'Php', 'makalesayisi' => 22)); $diller->insert(array('dil' => 'Ruby On Rails', 'makalesayisi' => 34)); $diller->insert(array('dil' => 'Linux', 'makalesayisi' => 56)); ?>
<?php #kayıtlı dil sayısını yazalım. echo "kayıtlı dil sayısı : ".$diller->count(); ?>
<?php #tüm dilleri çekelim. $dilListesi = $diller->find(); #kayıtlı dilleri listeleyelim. foreach($dilListesi as $dil) { printf('Dil : %s - Miktar : %s <br>', $dil['dil'], $dil['makalesayisi']); } ?>
<?php #koşulu belirleyelim. $where = array('makalesayisi' => '12'); #makalesayisi 12 olan dilleri çekelim. $dilListesi = $diller->find($where); #sonuçları listeleyelim. foreach($dilListesi as $dil) { printf('Dil : %s - Miktar : %s <br>', $dil['dil'], $dil['makalesayisi']); } ?>
<?php #Sıralamayı belirleyelim. (1 : ASC , -1 : DESC) $orderBy = array('dil' => -1); #limit ver orderBy metodlarını uygulayalım. $dilListesi = $diller->find()->limit(2)->orderBy($orderBy); ?>
<?php #eklenecek dil bilgilerini tanımlayalım. $yeniDil = array( 'dil' => 'Java', 'makalesayisi' => 122 ); try { $diller->insert($yeniDil); } catch(MongoCursorException $e) { die('Yeni dil eklenirken teknik bir sorunla karşılaşıldı ' . $e->getMessage()); } ?>
<?php #güncellenecek kaydın koşulunu belirleyelim. $where = array('dil' => 'Java'); #güncellenecek alanı belirleyelim. $guncelDil = array('makalesayisi' => 435); #içeriği güncelleyelim. $diller->update($where, $guncelDil); ?>
<?php #silenecek kaydın koşullarını belirliyoruz. $where = array('dil' => 'Android'); #kaydı collection içerisinden siliyoruz. $diller->remove($where); ?>
<?php #silinecek collectionun belirleyelim. $diller->drop(); ?>
<?php $db->dropDatabase(); ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" > <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:padding="10dp" android:src="@drawable/ic_launcher" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:ems="10" /> <TextView android:id="@+id/TextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/editText" android:layout_centerHorizontal="true" android:layout_marginBottom="17dp" android:padding="10dp" android:gravity="center" android:text="@string/sampletext" /> <ImageView android:id="@+id/yazilimdersiheaderImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:src="@drawable/logo" /> </RelativeLayout>Uygulamanın ekran görüntüsü aşağıdaki gibi olacaktır.
public class MainActivity extends Activity { public Button openbrowserButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = (EditText) findViewById(R.id.editText); editText.setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { Toast.makeText(MainActivity.this, editText.getText(), Toast.LENGTH_LONG).show(); return true; } else if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_5)) { Toast.makeText(MainActivity.this, "5 tuşuna basıldı!", Toast.LENGTH_LONG).show(); return true; } return false; } }); } }Yukarıdaki kodlamada gördüğünüz üzere cursor EditText alanında iken KeyEvent.KEYCODE_ENTER tıklanıldığında Toast mesajında EditText içerisinde yazılı olan ifadelerin gösterimi sağlandı. Eğer kullanıcı 5 tuşuna basarsa, Toast mesajı olarak "5 tuşuna basıldı!" mesajının gösterimi sağlandı. Kodlamada 5 rakamının algılanmasını ise KeyEvent.KEYCODE_5 ile sağlayabiliyoruz. Örnek EditText Uygulaması ile alakalı kodu aşağıdaki butona tıklayarak indirebilirsiniz:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#FFFFFF" android:layout_height="match_parent" > <Button android:id="@+id/displayOpenBrowserButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="20dp" android:text="@string/open_browser" /> <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:padding="10dp" android:src="@drawable/ic_launcher" /> </RelativeLayout>Uygulamanın ekran görüntüsü aşağıdaki gibi olacaktır.
public class MainActivity extends Activity { public Button openbrowserButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); openbrowserButton= (Button) findViewById(R.id.displayOpenBrowserButton); openbrowserButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.yazilimdersi.info")); startActivity(browserIntent); } }); } }Yukarıdaki kodlamada gördüğünüz üzere butona tıklanıldığında Intent metodu çağrılmakta ve startActivity ile browserin açılması sağlanmaktadır. Intent.ACTION_VIEW, çağrılacak olan activitynin görüntülenmek amacıyla kullanacağı belirlemektedir. Örnek Button Uygulaması ile alakalı kodu aşağıdaki butona tıklayarak indirebilirsiniz:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#FFFFFF" android:layout_height="match_parent" > <Button android:id="@+id/displayNormalToastMessageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="20dp" android:text="@string/display_normal_toast_message" /> <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:padding="10dp" android:src="@drawable/ic_launcher" /> </RelativeLayout>Uygulamanın ekran görüntüsü aşağıdaki gibi olacaktır.
public class MainActivity extends Activity { public Button displayNormalToastMessageButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); displayNormalToastMessageButton = (Button) findViewById(R.id.displayNormalToastMessageButton); displayNormalToastMessageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(), getString(R.string.normaltoastmesaji), Toast.LENGTH_LONG).show(); } }); } }Yukarıdaki kodlamada gördüğünüz üzere butona tıklanıldığında Toast.makeText(context,textmesajı,süre) metodu çağrılmaktadır. Context, çalışan uygulamayla alakalı ilgili contextin setlenmesiyle gerçekleştirilir. text mesajı, gösterilmesi planlanan mesajı ifade etmektedir. süre ise milisaniye cinsinden toastın gösterim sürecini belirlemede kullanılmaktadır. Burada süre olarak genelde Toast.LENGTH_LONG veya Toast.LENGTH_SHORT ifadeleri kullanılmaktadır. Normal Toast Uygulaması ile alakalı kodu aşağıdaki butona tıklayarak indirebilirsiniz:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#FFFFFF" android:layout_height="match_parent" > <Button android:id="@+id/displayCustomToastMessageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="20dp" android:text="@string/display_custom_toast_message" /> <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:padding="10dp" android:src="@drawable/ic_launcher" /> </RelativeLayout>
public class MainActivity extends Activity { public Button displayCustomToastMessageButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); displayCustomToastMessageButton = (Button) findViewById(R.id.displayCustomToastMessageButton); displayCustomToastMessageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { LayoutInflater inflater = getLayoutInflater(); View layout = inflater.inflate(R.layout.custom_toast, (ViewGroup) findViewById(R.id.mainLinearLayout)); ImageView image = (ImageView) layout.findViewById(R.id.yazilimdersiImageView); image.setImageResource(R.drawable.ic_launcher); TextView text = (TextView) layout.findViewById(R.id.customToastTextView); text.setText(getString(R.string.customtoastmesaji)); Toast toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER_VERTICAL, 0, 150); toast.setDuration(Toast.LENGTH_LONG); toast.setView(layout); toast.show(); } }); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:padding="20dp" > <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:src="@drawable/logo" /> <EditText android:id="@+id/usernameEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@drawable/customedittext" android:ems="10" android:hint="@string/username" android:inputType="textPersonName" android:textColor="#969696" android:textColorHint="#C7C7CD" android:textCursorDrawable="@null" > <requestFocus /> </EditText> <EditText android:id="@+id/passwordEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/usernameEditText" android:layout_centerHorizontal="true" android:layout_marginTop="20dp" android:background="@drawable/customedittext" android:ems="10" android:hint="@string/password" android:inputType="textPassword" android:textColor="#969696" android:textColorHint="#C7C7CD" android:textCursorDrawable="@null" /> <Button android:id="@+id/loginButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/passwordEditText" android:layout_centerHorizontal="true" android:layout_marginTop="10dp" android:background="#265376" android:padding="10dp" android:textSize="16sp" android:textColor="#FFFFFF" android:text="@string/loginText" /> <TextView android:id="@+id/registerTextView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/passwordEditText" android:layout_below="@+id/loginButton" android:layout_marginTop="10dp" android:clickable="true" android:gravity="center" android:singleLine="true" android:text="@string/register" android:textColor="#969696" android:textSize="14sp" /> </RelativeLayout>Kodlamada dikkat ederseniz Edit Textlerin görünümünde yenilik oluşturmak adına @drawable/customedittext dosyası kullanıldı. Bu dosyada yapılan kodlama sayesinde Android'in son sürümlerinde ortaya çıkan tasarım etkisi eski sürümlerde de gözlemlencek hale getirildi. Bu tasarım etkisinin oluşturulması için res/drawable/customedittext.xml dosyası oluşturup aşağıda bulunan kodlamayı dosya içerisine eklemeniz gerekmektedir.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="rectangle" > <solid android:color="#ABABAB" /> <padding android:bottom="1dp" /> </shape> </item> <item android:bottom="5dp"> <shape android:shape="rectangle" > <solid android:color="#fff" /> <padding android:left="1dp" android:right="1dp" /> </shape> </item> <item> <shape android:shape="rectangle" > <solid android:color="#fff" /> <padding android:left="8dp" android:top="4dp" android:bottom="4dp"/> </shape> </item> </layer-list>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" android:padding="20dp" > <ImageView android:id="@+id/yazilimdersiImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:src="@drawable/logo" /> <EditText android:id="@+id/usernameEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@drawable/customedittext" android:ems="10" android:hint="@string/username" android:inputType="textPersonName" android:textColor="#969696" android:textColorHint="#C7C7CD" android:textCursorDrawable="@null" > <requestFocus /> </EditText> <EditText android:id="@+id/emailEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/usernameEditText" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_marginTop="20dp" android:background="@drawable/customedittext" android:ems="10" android:hint="@string/email" android:inputType="textEmailAddress" android:textColor="#969696" android:textColorHint="#C7C7CD" android:textCursorDrawable="@null" > </EditText> <EditText android:id="@+id/passwordEditText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/emailEditText" android:layout_centerHorizontal="true" android:layout_marginTop="20dp" android:background="@drawable/customedittext" android:ems="10" android:hint="@string/password" android:inputType="textPassword" android:textColor="#969696" android:textColorHint="#C7C7CD" android:textCursorDrawable="@null" /> <Button android:id="@+id/registerButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/passwordEditText" android:layout_centerHorizontal="true" android:layout_marginTop="10dp" android:background="#265376" android:padding="10dp" android:text="@string/registerText" android:textColor="#FFFFFF" android:textSize="16sp" /> <TextView android:id="@+id/loginTextView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/passwordEditText" android:layout_below="@+id/registerButton" android:layout_marginTop="10dp" android:clickable="true" android:gravity="center" android:singleLine="true" android:text="@string/login" android:textColor="#969696" android:textSize="14sp" /> </RelativeLayout>Registration ekranın ekran görüntüsü aşağıdaki gibi olacaktır.
public class LoginActivity extends Activity { public TextView registerTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); registerTextView = (TextView) findViewById(R.id.registerTextView); registerTextView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(getApplicationContext(), RegisterActivity.class); startActivity(i); } }); } }Yukarıdaki kodlamada gördüğünüz üzere registrationTextView a tıklanıldığında startActivity() metodu sayesinde RegisterActivity.class çağrılmaktadır. Böylelikle Login ekranından Registration ekranına geçiş sağlanmaktadır.
public class RegisterActivity extends Activity { public TextView loginTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); loginTextView = (TextView) findViewById(R.id.loginTextView); loginTextView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }Yukarıdaki kodlamada gördüğünüz üzere loginTextView a tıklanıldığında finish() metodu sayesinde mevcut activity kapatılmakta ve daha önceden çağrılan LoginActivity.java ekranı çağrılmaktadır. Böylelikle Registration ekranından Login ekranına geçişte sağlandı.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yazilimdersi.info.example.registration" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > <activity android:name=".LoginActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".RegisterActivity" android:label="@string/app_name" > </activity> </application> </manifest>Tüm işlemlerin ardından proje üzerinde sağa tıklayıp Run As => 1 Android Applicationa tıklayarak projeyi çalıştırınız.
AlertDialog alertDialog = new AlertDialog.Builder( MainActivity.this).create(); // Dialogun başlığını ayarlayalım alertDialog.setTitle("Tek Butonlu Uyarı Dialogu"); // Dialogun içeriğini ayarlayalım alertDialog.setMessage("yazilimdersi.info sitesine hoşgeldiniz"); // Dialogun ikonunu ayarlayalım alertDialog.setIcon(R.drawable.home_normal); // Tamam butonunu ayarlayalım alertDialog.setButton("Tamam", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Toast.makeText(getApplicationContext(), "Tamam butonuna tıkladınız!", Toast.LENGTH_SHORT).show(); } }); // Dialogu görüntüleyelim alertDialog.show();Uygulamanın ekran görüntüsü aşağıdaki gibi olacaktır.
AlertDialog.Builder confirmDialog = new AlertDialog.Builder( MainActivity.this); // Dialogun başlığını ayarlayalım confirmDialog.setTitle("Müşteri Silme"); // Dialogun içeriğini ayarlayalım confirmDialog.setMessage("Silmek istediğinizden emin misiniz?"); // Dialogun ikonunu ayarlayalım confirmDialog.setIcon(R.drawable.home_normal); // Evet butonunu ayarlayalım confirmDialog.setPositiveButton("Evet", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { Toast.makeText(getApplicationContext(), "Evet butonuna tıkladınız", Toast.LENGTH_SHORT).show(); } }); // Hayır butonunu ayarlayalım confirmDialog.setNegativeButton("Hayır", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Toast.makeText(getApplicationContext(), "Hayır butonuna tıkladınız", Toast.LENGTH_SHORT).show(); dialog.cancel(); } }); // Dialogu görüntüleyelim confirmDialog.show();Uygulamanın ekran görüntüsü aşağıdaki gibi olacaktır.
AlertDialog.Builder confirmDialog = new AlertDialog.Builder( MainActivity.this); // Dialogun başlığını ayarlayalım confirmDialog.setTitle("Dosyayı Kaydet..."); // Dialogun içeriğini ayarlayalım confirmDialog.setMessage("Dosyayı kaydetmek ister misin?"); // Dialogun ikonunu ayarlayalım confirmDialog.setIcon(R.drawable.home_normal); // Evet butonunu ayarlayalım confirmDialog.setPositiveButton("Evet", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog,int which) { Toast.makeText(getApplicationContext(), "Evet butonuna tıkladınız", Toast.LENGTH_SHORT).show(); } }); // Hayır butonunu ayarlayalım confirmDialog.setNegativeButton("Hayır", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Toast.makeText(getApplicationContext(), "Hayır butonuna tıkladınız", Toast.LENGTH_SHORT).show(); } }); //İptal butonunu ayarlayalım
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_home" android:icon="@drawable/home_normal" android:title="Home" /> <item android:id="@+id/menu_conversation" android:icon="@drawable/conversation_normal" android:title="Conversations" /> <item android:id="@+id/menu_lastadded" android:icon="@drawable/lastadded_normal" android:title="Last Added" /> <item android:id="@+id/menu_videos" android:icon="@drawable/videos_normal" android:title="Videos" /> <item android:id="@+id/menu_more" android:icon="@drawable/more_normal" android:title="More" /> </menu>
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.layout.menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_home: Toast.makeText(MainActivity.this, "Home is Selected", Toast.LENGTH_SHORT).show(); return true; case R.id.menu_conversation: Toast.makeText(MainActivity.this, "Conversation is Selected", Toast.LENGTH_SHORT).show(); return true; case R.id.menu_lastadded: Toast.makeText(MainActivity.this, "Last Added is Selected", Toast.LENGTH_SHORT).show(); return true; case R.id.menu_videos: Toast.makeText(MainActivity.this, "Videos is Selected", Toast.LENGTH_SHORT).show(); return true; case R.id.menu_more: Toast.makeText(MainActivity.this, "More is Selected", Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); } } }
SELECT column FROM table ORDER BY RAND() LIMIT 1
SELECT column FROM table ORDER BY RANDOM() LIMIT 1
SELECT TOP 1 column FROM table ORDER BY NEWID()
SELECT column, RAND() as IDX FROM table ORDER BY IDX FETCH FIRST 1 ROWS ONLY
SELECT column FROM ( SELECT column FROM table ORDER BY dbms_random.value ) WHERE rownum = 1Gördüğünüz gibi farklı platformlarda SQL diline ait syntax farklılık gösterebilmektedir.
SELECT TOP 10 sütun FROM tablo
SELECT sütun FROM tablo LIMIT 10
SELECT sütun FROM tablo WHERE ROWNUM <= 10
SET rowcount 10 SELECT sütun FROM tablo
SELECT FIRST 10 sütun FROM tabloGördüğünüz gibi farklı platformlarda SQL diline ait syntax farklılık gösterebilmektedir. Eğer uygulamalarınızı veritabanı bağımsız şekilde kullanmak isterseniz Coldfusion bunu rahatlıkla sağlamaktadır. Yapmanız gereken aşağıda yazıldığı gibi cfquery etiketine maxrows parametresini setlemenizdir.
<cfquery datasource="#ds#" maxrows="10"> SELECT column FROM table </cfquery>
private void call(String telefonnumarasi) { try { Intent callIntent = new Intent(Intent.ACTION_CALL); callIntent.setData(Uri.parse("tel:" + telefonnumarasi)); startActivity(callIntent); } catch (ActivityNotFoundException e) { Log.e("TAG", "Call failed", e); } }
file_get_contens('http://yazilimdersi.info');Bu metod GET requesti ile sonuç dönen siteler için uygundur. Ancak POST ile gönderilmesi gereken isteklerde bu metod ne yazıkki hatayı handle etmenizde yeterli olmamaktadır. Burada curl metodu devreye girmektedir. Php curl metodunu çalıştırmanız için aşağıda açıklanan dört adımı takip etmeniz gerekmektedir:
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,"http://yazilimdersi.info"); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); //curl_setopt($ch,CURLOPT_HEADER, true); //if you want headersCURLOPT_URL -> Website içeriği getirilecek URL adresi
$output=curl_exec($ch);
curl_close($ch);
if(is_callable('curl_init')){ echo "curl aktif modda"; } else { echo "curl pasif modda"; }
function GetMetodu($url) { $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); // curl_setopt($ch,CURLOPT_HEADER, false); $output=curl_exec($ch); curl_close($ch); return $output; } echo GetMetodu("http://yazilimdersi.info");
function httpPost($url,$params) { $postData = ''; foreach($params as $k => $v) { $postData .= $k . '='.$v.'&'; } rtrim($postData, '&'); $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); curl_setopt($ch,CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_POST, count($postData)); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); $output=curl_exec($ch); curl_close($ch); return $output; }
$params = array( "name" => "Mustafa Çelik", "age" => "26", "location" => "Istanbul" ); echo httpPost("http://yazilimdersi.info/php/postcurl.php",$params);
function getRandomUserAgent() { $userAgents=array( "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)", "Opera/9.20 (Windows NT 6.0; U; en)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.50", "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr; rv:1.7) Gecko/20040624 Firefox/0.9", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/48 (like Gecko) Safari/48" ); $rastgele = rand(0,count($userAgents)-1); return $userAgents[$rastgele]; }
curl_setopt($ch,CURLOPT_USERAGENT,getRandomUserAgent());
function httpGetWithErros($url) { $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); $output=curl_exec($ch); if($output === false) { echo "Error Number:".curl_errno($ch)."<br>"; echo "Error String:".curl_error($ch); } curl_close($ch); return $output; }
SELECT sütun FROM tablo LIMIT 10
SELECT sütun FROM tablo LIMIT 10 OFFSET 20
function get_client_language($availableLanguages, $default='tr') { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $langs=explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']); foreach ($langs as $value){ $choice=substr($value,0,2); if(in_array($choice, $availableLanguages)){ return $choice; } } } return $default; }]]>
function konumlarArasiMesafeyiGetir($enlem1, $boylam1, $enlem2, $boylam2) { $theta = $boylam1 - $boylam2; $mil = (sin(deg2rad($enlem1)) * sin(deg2rad($enlem2))) + (cos(deg2rad($enlem1)) * cos(deg2rad($enlem2)) * cos(deg2rad($theta))); $mil = acos($mil); $mil = rad2deg($mil); $mil = $mil * 60 * 1.1515; $feet = $mil * 5280; $yard = $feet / 3; $kilometre = $mil * 1.609344; $metre = $kilometre * 1000; return compact('mil','feet','yard','kilometre','metre'); }Yukarıda hazırlanan metodda öncelikle parametre olarak girilen enlem boylam bilgilerinden boylam bilgilerinin birbirinden çıkarılması sağlanmıştır. Elde edilen değer ise deg2grad() fonksiyonu sayesinde dereceden radiusa dönüştürülmüştür. Ortaya çıkan değerin sin() ve cos() fonksiyonları ile sayesinde cosinüs ve sinüs değerleri elde edilmiştir. Aslında geometride kullanılan hipotenüs verisinin bulunmasında kullanılan yöntemin aynısı bu fonksiyonda da kullanılarak sonuç metre,kilometre,feet e yard ölçü birimlerine bağlı olarak elde edilmiştir. Fonksiyonu çağırmak için aşağıda bulunan kod parçacığını konumlarArasiMesafeyiGetir fonksiyonun hemen altına ekleyelim.
$konum1 = array('enlem' => 40.6167, 'boylam' => 43.1000); // Kars iline ait enlem-boylam bilgisi $konum2 = array('enlem' => 41.0136, 'boylam' => 28.9550); // İstanbul iline ait enlem-boylam bilgisi $mesafe = konumlarArasiMesafeyiGetir($konum1['enlem'], $konum1['boylam'], $konum2['enlem'], $konum2['boylam']); foreach ($mesafe as $birim => $deger) { echo $birim.': '.number_format($deger,4).'<br />'; }
mil: 739.3247 feet: 3,903,634.4912 yard: 1,301,211.4971 kilometre: 1,189.8278 metre: 1,189,827.7929
<?php function cleanInput($input) { $search = array( '@<script[^>]*?>.*?</script>@si', // Strip out javascript '@<[\/\!]*?[^<>]*?>@si', // Strip out HTML tags '@<style[^>]*?>.*?</style>@siU', // Strip style tags properly '@<![\s\S]*?--[ \t\n\r]*>@' // Strip multi-line comments ); $output = preg_replace($search, '', $input); return $output; } function sanitize($input) { if (is_array($input)) { foreach($input as $var=>$val) { $output[$var] = sanitize($val); } } else { if (get_magic_quotes_gpc()) { $input = stripslashes($input); } $input = cleanInput($input); $output = mysql_real_escape_string($input); } return $output; } ?>Yukarıdaki metod ile sisteme zarar verecek içeriklerden kurtulmuş oluruz. Aşağıda bulunan örnekle metodu nasıl çağıracağımızı inceleyelim ve nasıl bir sonuç aldığımızı görelim:
<?php $bad_string = "Hello! <script src='http://www.yazilimdersi.info/bad_script.js'></script> It's a good day!"; $good_string = sanitize($bad_string); // $good_string sonuç olarak "Hello! It\'s a good day!" verisini döner. // Bu metodu ayrıca POST ve GET isteklerinde de kullanabilirsiniz. $_POST = sanitize($_POST); $_GET = sanitize($_GET); ?>
$arabalar = array("Mercedes","BMW","Audi","Ferrari","Alfa Romeo"); Ayrıca aynı işlemi şu şekilde de ifade edebiliriz: $arabalar[0] = "Mercedes"; $arabalar[1] = "BMW"; $arabalar[2] = "Audi"; $arabalar[3] = "Ferrari"; $arabalar[4] = "Alfa Romeo";
Yukarıda diziler dikkat ederseniz key alanları 0,1,2,3,4 gibi rakamsal keylerden oluşmuştur. Ancak böyle olmak zorunda değillerdir. Bu key alanları anlamlı ifadelerle de tanımlanabilir. Mesela araçların model numaralarını baz alalım. Örnek yapı şu şekilde olabilir:
$arabalar = array( "MX120"=>"Mercedes" , "B12" => "BMW" , "A6" => "Audi" , "F6" => "Ferrari" , "AR900" => "Alfa Romeo" ); Bu tanım aslında şuna da karşılık gelmektedir: $arabalar["MX120"] = "Mercedes"; $arabalar["B12"] = "BMW"; $arabalar["A6"] = "Audi"; $arabalar["F6"] = "Ferrari"; $arabalar["AR900"] = "Alfa Romeo";
Gördüğünüz gibi dizilerin key alanlarına daha anlamlı ifadeler eklenebilmektedir. Ayrıca dize içerisinde dizilerde Php programlama dilinde yaygın kullanılan bir durumdur. Bu yapı sayesinde içiçe birçok dize tanımlaması yapılabilmektedir. Buna örnek verecek olursak ;
$arabalar = array( "pahalilar"=> array("Mercedes" , "Ferrari", "Audi"), "ucuzlar" => array("Toyota","Renault","Fiat") );
Eğer sizden ucuz arabaların listesini istersem tek yapmanız gereken $arabalar["ucuzlar"] değişkenine ait çıktıyı söylemenizdir. Eğer $arabalar["pahalilar"] değişkenini çağırırsanız pahali araçların isimleri listelenecektir.
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="http://feedburner.google.com/fb/a/mailverify" method="post" target="popupwindow" onsubmit="window.open('http://feedburner.google.com/fb/a/mailverify?uri=yazilimdersi', 'popupwindow', 'scrollbars=yes,width=550,height=520'); return true"> <p>E-Posta Adresiniz:</p> <p><input type="text" style="width:140px" name="email"/></p> <input type="hidden" value="yazilimdersi" name="uri"/> <input type="hidden" name="loc" value="en_US"/><input type="submit" value="Kaydol" /> <p>Delivered by <a href="http://feedburner.google.com" target="_blank">FeedBurner</a></p> </form>Yukarıda bulunan kod parçacığında yazilimdersi yerine size ait feedburner hesabının kullanıcı ismini girmeniz yeterli olacaktır. Böylelikle hatadan kurtulacaksınız.
<?php function getfacebooklikecount($url){ $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); $raw = curl_exec($ch); curl_close($ch); $data = json_decode($raw); $content = $data->likes; return $content; } $facebooklikes = getfacebooklikecount("http://graph.facebook.com/yazilimdersi"); echo $facebooklikes; ?>Yukarıdaki metodda görüldüğü üzere getfacebooklikecount($url) metoduna parametre olarak graph.facebook.com/yazilimdersi adresi verilmekte. curl_init metodu ile içeriğe erişilmektedir. Sonrasında json_decode metodu ile json formatındaki veri çözümlenip $data->likes ile sayfanın beğeni sayısı çekilmektedir. Sizde artık aynı fonksiyona parametre olarak kendi sitenize ait facebook linkini ekleyebilir ve beğeni sayısını online olarak facebook serverlerinden çekebilirsiniz.]]>
<?php $baglanti = mysql_connect( "sunucu ip adresi", "kullanıcı adı", "şifre" ); if ( !$baglanti ) exit( "Veritabanı ile bağlantı sağlanamadı." ); ?>
<?php $baglanti = mysql_connect( "sunucu ip adresi", "kullanıcı adı", "şifre" ); if ( !$baglanti ) exit( "Veritabanı ile bağlantı sağlanamadı." ); mysql_select_db( "yazilimdersi" ); ?>
<?php mysql_query( "INSERT INTO kullanici_bilgisi (isim,soyisim,meslek,durum) VALUES('Serkan','Karataş','Muhasebeci','1');" ); ?>
<?php $baglanti = mysql_connect( "sunucu ip adresi", "kullanıcı adı", "şifre" ); if ( !$baglanti ) exit( "Veritabanı ile bağlantı sağlanamadı." ); mysql_select_db( "yazilimdersi" ); $sorgu = mysql_query( "SELECT * FROM kullanici_bilgisi WHERE durum = '1';" ); while( $row = mysql_fetch_array( $sorgu ) ) { echo $row['isim']." ".$row['soyisim']. " ın mesleği : " . $row['meslek']; } mysql_close(); ?>
<?php $alici = "[email protected]"; $baslik = "yazilimdersi.info sitesine hoşgeldiniz"; $mesaj = "Merhaba Serap Hanım \n YazılımDersi sitesinde farklı programlama dilleriyle ilişkili birçok döküman bulabilirsiniz."; $gonderen = "[email protected]"; $ayarlar = "From: $gonderen"; mail( $alici, $baslik, $mesaj, $ayarlar ); ?>
<?php session_start(); $_SESSION['kullanici_adi'] = "Serap"; ?>
<?php session_start(); if ( isset( $_SESSION['sayac'] ) ) $_SESSION['sayac'] = $_SESSION['sayac'] + 1; else $_SESSION['sayac'] = 1; echo "Bu sayfa " . $_SESSION['sayac'] . " kez görüntülendi."; ?>
<?php unset( $_SESSION['sayac'] ); ?>
// setcookies ( isim, deger, süre) şeklinde kullanılmaktadır.
setcookie( "language", "tr", time() + (24*3600) ); // 1 gün geçerlidir.
<?php echo $_COOKIE['language']; // language adlı çerezin değerini getirir. ?>
<?php print_r( $_COOKIE ); // Kullanıcıya ait sitenizle alakalı tüm çerezler listelenecektir. ?>
<?php setcookie( "language", "tr", time() - 3600 ); // çerez 1 saatten fazla geçmiş olacaktır. ?>
<?php echo "<html> <head> <title>YazılımDersi.info</title> </head> <body>"; ?>
<?php echo "Test Mesajı"; ?>
<?php echo "</body></html>"; ?>
<?php include("header.php"); include("main.php"); include("footer.php"); ?>
<html> <head> <title>YazilimDersi.info </head> <body> Test Mesajı </body> </html>]]>
<?php date('d.m.Y H:i'); // d->(gün) m->ay Y->yıl H->saat i->dakikaya karşılık gelmektedir. Çıktı olarak ise aşağıdaki sonuç elde edilmektedir: 14.08.2014 01:54 ?>Zaman damgası kullanılarak yapılan çalışmaya örnek olarak ise aşağıdaki kodlama kullanılabilir.
<?php echo time(); // o anki zaman dilimini UNIX zaman dilimine uygun şekilde gösterir 141611541 gibi. echo date("d/m/Y H:i:s", time()); // Bu kod ise mevcut zaman dilimini belirlenen formatta gösterir. 13/05/2014 11:10:04 gibi ?>Ayrıca mktime() fonksiyonu kullanılarak mevcut zaman diliminden 1 gün,2 hafta,9 yıl önceye veya sonraya gitmenizi sağlayabilmektedir. Örneğin bulundugunuz günden 2 gün öncesini ekrana yazdıralım:
<?php $ikigunonce = mktime(0,0,0,date("m"),date("d")-2,date("Y")); echo date("d/m/Y G:i:s", $ikigunonce); // İki gün önceki zamanı verir. ?>
biçim karakteri |
Açıklama | Örnek sonuç |
---|---|---|
Gün | --- | --- |
d | Ay günlerinin sıfır dolgulu iki haneli gösterimi | 01'den 31'e |
D | Ay günlerinin üç harfli metinsel gösterimi | Pzt'den Paz'a |
j | Ay günlerinin sıfır dolgusuz gösterimi | 1'den 31'e |
l (küçük 'L' harfi) | Hafta günlerinin tam metinsel gösterimi | Pazar'dan Cumartesi'ye |
N | Hafta günlerinin ISO-8601 standardında sayısal gösterimi (PHP 5.1.0'da eklenmiştir) | 1'den (Pazartesi için) 7'ye (Pazar için) |
S | Ay günleri için 2 karakterli İngilizce sıralama ekleri | st, nd, rd ya da th. j ile uyumlu çalışmaktadır. |
w | Hafta günlerinin sayısal gösterimi | 0'dan (Pazar için) 6'ya (Cumartesi için) |
z | Yılın günleri (0'dan başlar) | 0'dan 365'e |
Hafta | --- | --- |
W | ISO-8601 standartına göre yılın hafta numarası, hafta başlangıcı Pazartesi'dir (PHP 4.1.0 sürümüyle eklenmiştir) | Örneğin: 42 (Yılın 42'inci haftası) |
Ay | --- | --- |
F | Ayın tam metinsel gösterimi, Ocak ya da Mart gibi | January'den December'a |
m | Ayın sıfır dolgulu sayısal gösterimi | 01'den 12'ye |
M | Ayın üç karakterli, metinsel kısa gösterimi | Jan'dan Dec'e kadar |
n | Ayın sıfır dolgusuz sayısal gösterimi | 1'den 12'ye kadar |
t | Belirtilen ayın gün sayısı | 28'den 31'e |
Yıl | --- | --- |
L | Artık yıl olduğunda | Eğer artık yılsa 1, değilse 0. |
o | ISO-8601 standardı yıl numarası. ISO hafta numaralarının (W) ait olduğu yılın gösterilmesi dışında Y ile aynı değere sahiptir. (PHP 5.1.0 sürümünde eklenmiştir) | Örnekler: 1999 ya da 2003 gibi |
Y | Yılın 4 haneli sayısal, tam gösterimi | Örnekler: 1999 ya da 2003 gibi |
y | Yılın iki haneli gösterimi | Örnekler: 99 ya da 03 gibi |
Saat | --- | --- |
a | Küçük harfli öğleden önce ve öğleden sonra | am ya da pm |
A | Büyük harfli öğleden önce ve öğleden sonra | AM ya da PM |
B | Swatch İnternet saati | 000'dan 999'a |
g | Saatin, 12-saatlik sıfır dolgusuz gösterimi | 1'den 12'ye |
G | Saatin, 24-saatlik sıfır dolgusuz gösterimi | 0'dan 23'e |
h | Saatin, 12-saatlik sıfır dolgulu gösterimi | 01'den 12'ye |
H | Saatin, 24-saatlik sıfır dolgulu gösterimi | 00'dan 23'e |
i | Sıfır dolgulu dakika gösterimi | 00 ile 59 arasında |
s | Sıfır dolgulu saniye gösterimi | 00 ile 59 arasında |
u | Mikrosaniye (PHP 5.2.2 sürümüyle eklenmiştir) | Örneğin: 654321 |
Zaman dilimi | --- | --- |
e | Zaman dilimi belirteci (PHP 5.1.0 sürümüyle eklenmiştir) | Örnekler: UTC, GMT, Europe/Istanbul |
I (büyük ı) | Yaz saati uygulaması var mı? | Varsa 1, yoksa 0. |
O | Saat olarak Greenwich zamanı (GMT) farkı | Örneğin: +0200 |
P | Saat ve dakika olarak Greenwich zamanı (GMT) farkı (PHP 5.1.3 sürümüyle eklenmiştir) | Örneğin: +02:00 |
T | Zaman dilimi kısaltması | Örnekler: EST, EET gibi |
Z | Saniye cinsinden saat farkı. UTC'nin batısı daima negatif, doğusu ise daima pozitif değerlidir. | -43200'den 50400'e |
wget http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
mysql -u root -p
CREATE DATABASE wordpress; Query OK, 1 row affected (0.00 sec)
CREATE USER wordpressuser@localhost; Query OK, 0 rows affected (0.00 sec)
SET PASSWORD FOR wordpressuser@localhost= PASSWORD("sifre"); Query OK, 0 rows affected (0.00 sec)
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost IDENTIFIED BY 'sifre'; Query OK, 0 rows affected (0.00 sec)
FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec)
mysql -u root -p
CREATE DATABASE wordpress; Query OK, 1 row affected (0.00 sec)
CREATE USER wordpressuser@localhost; Query OK, 0 rows affected (0.00 sec)
SET PASSWORD FOR wordpressuser@localhost= PASSWORD("sifre"); Query OK, 0 rows affected (0.00 sec)
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost IDENTIFIED BY 'sifre'; Query OK, 0 rows affected (0.00 sec)
FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec)
cp ~/wordpress/wp-config-sample.php ~/wordpress/wp-config.php
sudo nano ~/wordpress/wp-config.php
// ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define('DB_NAME', 'wordpress'); /** MySQL database username */ define('DB_USER', 'wordpressuser'); /** MySQL database password */ define('DB_PASSWORD', 'sifre');
sudo rsync -avP ~/wordpress/ /var/www/
cd /var/www/
sudo chown yenikullaniciadi:www-data /var/www -R sudo chmod g+w /var/www -R
sudo apt-get install php5-gd
http://149.86.54.10/wp-admin/install.php
sudo adduser yenikullaniciadi
sudo passwd yenikullaniciadi
sudo /usr/sbin/visudo
## Allow root to run any commands anywhere root ALL=(ALL) ALL yenikullaniciadi ALL=(ALL) ALL
sudo userdel yenikullaniciadi
sudo userdel -r yenikullaniciadi
sudo adduser yenikullaniciadi
sudo /usr/sbin/visudo
# User privilege specification root ALL=(ALL:ALL) ALL yenikullaniciadi ALL=(ALL:ALL) ALL
sudo userdel yenikullaniciadi
sudo rm -rf /home/yenikullaniciadi
sudo apt-get install git-core
sudo apt-get update
sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev build-essential
wget https://git-core.googlecode.com/files/git-1.8.5.5.tar.gz
tar -zxf git-1.8.5.5.tar.gz cd git-1.8.5.5.tar.gz
git clone git://git.kernel.org/pub/scm/git/git.git
sudo nano ~/.gitconfig
git config --global user.name "Kullanıcı Adınız" git config --global user.email [email protected]
git config --list
[master 0d9d21d] initial project version Committer: root Your name and email address were configured automatically based on your username and hostname. Please check that they are accurate. You can suppress this message by setting them explicitly: git config --global user.name "Your Name" git config --global user.email [email protected] After doing this, you may fix the identity used for this commit with: git commit --amend --reset-author
sudo yum install httpd
sudo service httpd start
ifconfig eth0 | grep inet | awk '{ print $2 }'
sudo yum install mysql-server sudo service mysqld start
sudo /usr/bin/mysql_secure_installation
Enter current password for root (enter for none): OK, successfully used password, moving on...
By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up...
sudo yum install php php-mysql
yum search php-
php-bcmath.x86_64 : A module for PHP applications for using the bcmath library php-cli.x86_64 : Command-line interface for PHP php-common.x86_64 : Common files for PHP php-dba.x86_64 : A database abstraction layer module for PHP applications php-devel.x86_64 : Files needed for building PHP extensions php-embedded.x86_64 : PHP library for embedding in applications php-enchant.x86_64 : Human Language and Character Encoding Support php-gd.x86_64 : A module for PHP applications for using the gd graphics library php-imap.x86_64 : A module for PHP applications that use IMAP [...]
sudo yum install 'modülün ismi' sudo yum install php-cli.x86_64 #php icin komut satırının ayarlanmasını saglar.
sudo nano /var/www/html/info.php
<?php phpinfo(); ?>
sudo chkconfig httpd on sudo chkconfig mysqld on
sudo apt-get update
sudo apt-get install curl
\curl -L https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
rvm requirements
rvm install ruby
rvm use ruby --default
rvm rubygems current
gem install rails
sudo apt-get update sudo apt-get install apache2
ifconfig eth0 | grep inet | awk '{ print $2 }'
sudo apt-get install mysql-server libapache2-mod-auth-mysql php5-mysql
sudo mysql_install_db
sudo /usr/bin/mysql_secure_installation
Enter current password for root (enter for none): OK, successfully used password, moving on...
By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up...
sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt
sudo nano /etc/apache2/mods-enabled/dir.conf
<IfModule mod_dir.c> DirectoryIndex index.php index.html index.cgi index.pl index.php index.xhtml index.htm </IfModule>
apt-cache search php5-
php5-cgi - server-side, HTML-embedded scripting language (CGI binary) php5-cli - command-line interpreter for the php5 scripting language php5-common - Common files for packages built from the php5 source php5-curl - CURL module for php5 php5-dbg - Debug symbols for PHP5 php5-dev - Files for PHP5 module development php5-gd - GD module for php5 php5-gmp - GMP module for php5 php5-ldap - LDAP module for php5 php5-mysql - MySQL module for php5 php5-odbc - ODBC module for php5 php5-pgsql - PostgreSQL module for php5 php5-pspell - pspell module for php5 php5-recode - recode module for php5 php5-snmp - SNMP module for php5 php5-sqlite - SQLite module for php5 php5-tidy - tidy module for php5 php5-xmlrpc - XML-RPC module for php5 php5-xsl - XSL module for php5 php5-adodb - Extension optimising the ADOdb database abstraction library php5-auth-pam - A PHP5 extension for PAM authentication [...]
sudo apt-get install 'modülün ismi' sudo apt-get install php5-mysql #mysql bağlantısını sağlayacak olan modülün kurulumunda kullanılacak komut
sudo nano /var/www/info.php
<?php phpinfo(); ?>
sudo service apache2 restart
sudo apt-get install apache2
sudo mkdir -p /var/www/yazilimdersi.info/public_html
sudo chown -R $USER:$USER /var/www/yazilimdersi.info/public_html
sudo chmod -R 755 /var/www
sudo nano /var/www/yazilimdersi.info/public_html/index.html
<html> <head> <title>www.yazilimdersi.info</title> </head> <body> <h1>Virtual Host ile alakalı kurulum başarılı şekilde gerçekleştirildi.</h1> </body> </html>
sudo cp /etc/apache2/sites-available/default /etc/apache2/sites-available/yazilimdersi.info
sudo nano /etc/apache2/sites-available/yazilimdersi.info
ServerName yazilimdersi.info
ServerAlias www.yazilimdersi.info
DocumentRoot /var/www/yazilimdersi.info/public_html
<VirtualHost *:80> ServerAdmin [email protected] ServerName yazilimdersi.info ServerAlias www.yazilimdersi.info DocumentRoot /var/www/yazilimdersi.info/public_html [...]
sudo a2ensite yazilimdersi.info
<?php echo phpinfo(); ?>Php dosyasına yapılan eklemelerden sonra oluşan phpinfo.php dosyasını C://wamp/www/ dizini altına taşıyalım. Sonrasında browsera http://localhost/phpinfo.php linkini yazdığımızda kurduğumuz Wamp Server ile alakalı tüm bilgiler listelencektir. Hangi Php versiyonunu kurdugumuz, desteklediği modüller, çalışan portlar vs. birçok bilgiye buradan ulaşabilirsiniz.
http://localhost:1453]]>
Intent i = new Intent(getApplicationContext(), İkinciEkran.class); startActivity(i);
Intent i = new Intent(getApplicationContext(), İkinciEkran.class); i.putExtra("key", "value"); // Örneğin aşağıdaki email adresi gönderiminde kullanıldığı datalar iletilmektedir. // Key = 'email' // value = '[email protected]' i.putExtra("email", "[email protected]"); startActivity(i);
Intent i = getIntent(); i.getStringExtra("key"); // email adresi gönderilen bilginin activity üzerinde alınması // ve emailadresim değişkeninde setlenmesi örnekteki gibidir. String emailadresim = i.getStringExtra("email");
Intent i = new Intent(getApplicationContext(), İkinciEkran.class); startActivityForResult(i, 1453); // 1453 bir sonraki activityden gelen datanın olumlu olup olmadığında kullanılacaktır. // Yeni oluşturulan activityden gelen datanın okunmasında onActivityResult() kullanılmaktadır. @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode == 1453){ // website verisinin yeni activityden çekilmesi şu şekilde olmaktadır. String websitem = data.getExtras().get("website"); } }Yukarıda bulunan kodlama ilk ekranda kullanılmaktadır. İkinciEkran.classında ise kullanılması gereken veri ise şu şekilde hazırlanmaktadır:
Intent i = new Intent(); // Websitesi bilgisini 'yazilimdersi.info' olarak aşağıdaki şekilde tanımlayarak göndermekteyiz: i.putExtra("website", "yazilimdersi.info"); // setResult alanında 1453 olarak setleme yapılması gerekmektedir. setResult(1453,in);
finish();
<activity android:name=".OrnekActivity"></activity>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical" > <TextView android:id="@+id/nameTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:textSize="18sp" android:text="İsim : " /> <EditText android:id="@+id/nameEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" > <requestFocus /> </EditText> <TextView android:id="@+id/emailTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:textSize="18sp" android:text="Email :" /> <EditText android:id="@+id/emailEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" /> <Button android:id="@+id/sonrakiEkranButton" android:layout_width="fill_parent" android:layout_marginTop="10dp" android:layout_height="wrap_content" android:text="Sonraki Ekrana Geç" /> </LinearLayout>
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class IlkEkranActivity extends Activity { EditText inputIsim; EditText inputEmail; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ekran1); inputIsim = (EditText) findViewById(R.id.nameEditText); inputEmail = (EditText) findViewById(R.id.emailEditText); Button sonrakiEkranButton = (Button) findViewById(R.id.sonrakiEkranButton); //Butona tıklanıldıgında alınacak aksiyonun yazılması sonrakiEkranButton.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { //Starting a new Intent Intent sonrakiEkran = new Intent(getApplicationContext(), IkinciEkranActivity.class); //Bilginin diğer aktivitelere iletilmesi sonrakiEkran.putExtra("isim", inputIsim.getText().toString()); sonrakiEkran.putExtra("email", inputEmail.getText().toString()); Log.e("n", inputIsim.getText()+"."+ inputEmail.getText()); startActivity(sonrakiEkran); } }); }}
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; public class IkinciEkranActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ekran2); TextView txtIsim = (TextView) findViewById(R.id.txtIsim); TextView txtEmail = (TextView) findViewById(R.id.txtEmail); Button kapatButton = (Button) findViewById(R.id.kapatButton); Intent i = getIntent(); // Bilgilerin önceki activityden alınması String isim = i.getStringExtra("isim"); String email = i.getStringExtra("email"); Log.e("Second Screen", isim + "." + email); // İlk activityden alınan bilgilerin görüntülenmesinde kullanılmaktadır. txtIsim.setText(isim); txtEmail.setText(email); // Kapatma butonun alacağı aksiyonun belirlenmesi kapatButton.setOnClickListener(new View.OnClickListener() { public void onClick(View arg0) { //İkinci Activity nin kapatılması finish(); } }); } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:padding="10dp" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:textSize="18sp" android:text="Önceki Activityde girdiğiniz bilgier :" /> <TextView android:id="@+id/txtIsim" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:textSize="18sp"/> <TextView android:id="@+id/txtEmail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#FFF" android:textSize="18sp" /> <Button android:id="@+id/kapatButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Kapat" /> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yazilimdersi.info.androidactivitygecisi" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".IlkEkranActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".IkinciEkranActivity"> </activity> </application> </manifest>
SELECT * FROM names;
+----+--------+
| id | name |
+----+--------+
| 1 | java |
| 2 | php |
| 3 | linux |
| 4 | java |
| 5 | java |
| 6 | ruby |
| 6 | java |
+----+--------+
ALTER TABLE names ADD CONSTRAINT name_ID UNIQUE (name)
SELECT DISTINCT name FROM names;
+------+ | name | +------+ | java | | php | | linux | | ruby | +-----+
DELETE n1 FROM names n1, names n2 WHERE n1.id < n2.id AND n1.name = n2.name
]]>
CREATE USER 'kullanıcı adı'@'localhost' IDENTIFIED BY 'şifre'2. MySQL'de kullanıcı silme:
DROP USER 'kullanıcı adı';3. MySQL'de kullanıcı listeleme:
SELECT host, user FROM mysql.user;4. MySQL'de kullanıcı yetkilendirme:
GRANT ALL PRIVILEGES ON 'veritabanı ismi' . 'tablo ismi' TO 'kullanıcı adı'@'localhost';
GRANT ALL PRIVILEGES ON * . * TO 'kullanıcı adı'@'localhost';
FLUSH PRIVILEGES;]]>
crontab -e
crontab -l
crontab -r
* * * * * /calıstirilacak komut
.---------------- dakika (0 - 59) | .------------- saat (0 - 23) | | .---------- Ayın Günleri (1 - 31) | | | .------- Ay (1 - 12) | | | | .---- Haftanın Günleri (0 - 6) (Pazar=0 ya da 7) | | | | | * * * * * Çalıştırılacak komut
*/30 * * * * /komut
00 08-18 * * * /komut
*/5 * * * * /komut
0 * * * * /komut
sudo apt-get install vpnc
IPSec gatewayIPSec ID IPSec secret IKE Authmode hybrid Xauth username Xauth password <şifre>
vpnc /etc/vpnc/xxx.conf
vpnc-disconnect
find / -name game
find /home -user yazilimdersi
find /usr -name *stat
find /var/spool -mtime +60
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> .... </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#359bed" android:orientation="vertical" android:padding="20dp" > <TextView android:id="@+id/emailTextView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="5dp" android:text="Email :" android:textColor="#FFFFFF" android:textSize="18sp" /> <EditText android:id="@+id/emailEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Email adresinizi girin" android:inputType="textEmailAddress" android:ems="10" > <requestFocus /> </EditText> <EditText android:id="@+id/passwordEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Şifrenizi girin" android:inputType="textVisiblePassword" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/saveButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Login" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/createAccountButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Yeni Hesap" /> <Button android:id="@+id/forgetpasswordButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Şifremi unuttum" /> </LinearLayout> </LinearLayout>
import android.app.Activity; import android.os.Bundle; public class AndroidLayoutsActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.linear_layout); } }
<Button android:id="@+id/btnLogin"> </Button> <Button android:id="@+id/btnCancel" android:layout_toRightOf="@id/btnLogin" android:layout_alignTop="@id/btnLogin"> </Button>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#359bed" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="20dp" > <TextView android:id="@+id/emailTextView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="5dp" android:text="Email :" android:textColor="#FFFFFF" android:textSize="18sp" /> <EditText android:id="@+id/emailEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@+id/emailTextView" android:layout_below="@+id/emailTextView" android:ems="10" android:hint="Email adresinizi girin" android:inputType="textEmailAddress" > <requestFocus /> </EditText> <Button android:id="@+id/loginButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/emailEditText" android:layout_below="@+id/emailEditText" android:layout_alignParentLeft="true" android:layout_marginRight="10px" android:text="Login" /> <Button android:id="@+id/cancelButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/emailEditText" android:layout_toRightOf="@+id/loginButton" android:text="Cancel" /> <Button android:id="@+id/registerButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:text="Register New Account" /> </RelativeLayout>
import android.app.Activity; import android.os.Bundle; public class AndroidLayoutsActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.relative_layout); } }
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/golden_gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="En altta text" /> </FrameLayout>
requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
<activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
Sabit | Açıklama |
---|---|
E_ERROR |
Ölümcül çalışma anı hataları. Bellek ayırma sorunu gibi giderilemeyen hatalar bu sınıfa girer. Böyle hatalar betiğin çalışmasının durmasına sebep olur. |
E_WARNING |
Çalışma anı uyarıları (ölümcül olmayan hatalar). Betiğin çalışması durmaz. |
E_PARSE |
Derleme anı çözümleme hataları. Çözümleme hatalarını sadece çözümleyici üretir. |
E_NOTICE |
Çalışma anı bildirimleri. Betikte bir hataya sebep olabilecek fakat betiğin normal çalışmasını esnasında oluşmayabilecek bir şeylerin saptandığını belirtir. |
E_ALL |
Desteklenen (PHP 6'da E_STRICT dışında kalan) tüm hatalar ve uyarılar. |
error_reporing(E_ALL); ini_set('display_errors','1');Eğer sadece kodunuzun çalışmasına sebep olan hataların görüntülenmesini istiyorsanız, bu durumda sadece aşağıdaki kod parçacığını eklemeniz yeterli olacaktır:
error_reporing(E_ERROR); ini_set('display_errors','1');Bu tip kod parçacıklarını direkt php kodunuzda tanımlayabileceğiniz gibi ayrıca serverinizde tanımlayabilirsiniz. Apache kurulu olan serverinizde php.ini dosyasına