web-gelistirme-sc.com

PHP'de mysql_ * fonksiyonlarını neden kullanmamalıyım?

mysql_* işlevlerini kullanmamanın nedeninin teknik nedenleri nelerdir? (örneğin, mysql_query(), mysql_connect() veya mysql_real_escape_string())?

Sitemde çalışıyor olsalar bile neden başka bir şey kullanmalıyım?

Sitemde çalışmıyorlarsa neden böyle hatalar alıyorum? 

Uyarı: mysql_connect (): Böyle bir dosya veya dizin yok

2308
Madara Uchiha

MySQL uzantısı:

  • Aktif gelişme altında değil
  • resmen kullanımdan kaldırıldı PHP 5.5'ten (Haziran 2013’te yayımlandı).
  • kaldırıldı tamamen PHP 7,0 (Aralık 2015’de yayımlandı) Oldu.
    • Bu, 1 Aralık 2018 itibariyle PHP'nin desteklenen bir sürümünde bulunmadığı anlamına gelir. Onu destekleyen PHP sürümünü kullanıyorsanız, güvenlik sorunlarını düzelten bir sürüm kullanıyorsunuzdur.
  • OO arabirimi yoksundur.
  • Desteklemiyor:
    • Engellenmeyen, zaman uyumsuz sorgular
    • Hazırlanan ifadeler veya parametreli hale getirilmiş sorgular
    • Saklı yordamlar
    • Birden çok ifade
    • Işlemler
    • "Yeni" şifre doğrulama yöntemi (varsayılan olarak MySQL 5.6'da açık; 5.7'da zorunludur)
    • MySQL 5.1 veya sonraki sürümlerindeki yeni işlevlerden herhangi biri

Kullanımdan kaldırıldığı için, kullanılması kodunuzu daha az geleceğe hazır hale getirir.

Hazırlanan ifadeler için destek eksikliği, harici veriden kaçmak ve ayrı bir işlev çağrısı ile elle kaçmaktan daha açık, daha az hataya açık bir yöntem sunarlar.

SQL uzantılarının karşılaştırmasını görün .

2008
Quentin

PHP, MySQL'e bağlanmak için üç farklı API sunuyor. Bunlar mysql (PHP 7'den kaldırıldı), - mysqli ve PDO uzantılarıdır.

mysql_* işlevleri çok popülerdi, ancak kullanımı artık teşvik edilmiyor. Belgelendirme ekibi veritabanı güvenlik durumunu tartışıyor ve kullanıcıları yaygın olarak kullanılan ext/mysql uzantısından uzaklaşmaları konusunda eğitmek bunun bir parçası (php.internals: deprecating ext/mysql işaretini kontrol edin).

Ve daha sonra PHP geliştirici ekibi, E_DEPRECATED kullanıcılar MySQL'e bağlanırken, mysql_connect(), mysql_pconnect() veya ext/mysql içine yerleştirilmiş örtük bağlantı işlevselliği aracılığıyla hatalar oluşturmaya karar verdi.

ext/mysql, PHP 5.5 itibariyle resmen onaylanmadı ve PHP 7 sürümünden kaldırıldı .

Kırmızı Kutuya Bakın?

Herhangi bir mysql_* işlevi manuel sayfasına gittiğinizde, artık kullanılmaması gerektiğini açıklayan kırmızı bir kutu görürsünüz.

Neden


ext/mysql'den uzaklaşmak yalnızca güvenlikle ilgili değil, aynı zamanda MySQL veritabanının tüm özelliklerine erişime sahip olmakla da ilgilidir.

ext/mysqlMySQL 3.2 için oluşturuldu ve o zamandan bu yana yalnızca çok az ekleme yapıldı. ext/mysql tarafından desteklenmeyen eksik özellikler şunlardır: (PHP kılavuzundan).

mysql_* işlevini kullanmama nedeni:

  • Aktif gelişme altında değil
  • PHP 7 tarihinden itibaren kaldırıldı
  • OO arayüzünden yoksun
  • Engellenmeyen, zaman uyumsuz sorguları desteklemiyor
  • Hazırlanan ifadeleri desteklemiyor mu veya parametreli hale getirilmiş sorgular
  • Saklı yordamları desteklemiyor
  • Birden fazla ifadeyi desteklemiyor
  • Desteklemiyor işlemler
  • MySQL 5.1'deki tüm işlevleri desteklemiyor

Quentin’nin cevabından alıntılananın üstünde

Hazırlanan ifadeler için destek eksikliği, harici verileri kaçmak ve ayrı bir işlev çağrısı ile manuel olarak kaçmak yerine açık ve daha az hataya açık bir yöntemle ifade ettiği için özellikle önemlidir.

Bakınız (SQL uzantılarının karşılaştırılması .


Kullanımdan kaldırılma uyarılarını engelleme

Kod MySQLiPDO'ye dönüştürülürken, E_DEPRECATED hataları, error_reporting öğesini hariç tutmak için php.ini öğesinde E_DEPRECATED: öğesinin ayarlanmasıyla gizlenebilir.

error_reporting = E_ALL ^ E_DEPRECATED

Bunun, MySQL dışındaki şeyler için de olabilir, diğer kullanım dışı uyarılar öğesini de gizleyeceğini unutmayın. (_/ PHP el kitabından)

PDO vs. MySQLi makalesi: Hangisini Kullanmalısınız? - Dejan Marjanovic seçmenize yardımcı olacaktır.

Ve daha iyi bir yol PDO ve şimdi basit bir PDO öğretici yazıyorum.


Basit ve kısa bir PDO öğreticisi


S. Aklımdaki ilk soru şuydu: “PDO” nedir?

A. “PDO - PHP Veri Nesneleri - birden çok veritabanına tek tip erişim yöntemi sağlayan bir veritabanı erişim katmanıdır.”

alt text


MySQL'e Bağlanma

mysql_* işleviyle veya bunu eski yoldan söyleyebiliriz (PHP 5.5 ve üstü kullanımdan kaldırılmıştır)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

PDO ile: Yapmanız gereken tek şey yeni bir PDO nesnesi oluşturmak. Yapıcı, veritabanı kaynağını belirtmek için parametreleri kabul eder PDO 'ın yapıcısı çoğunlukla DSN (veri kaynağı adı) ve isteğe bağlı olarak username, password olan dört parametre alır.

Burada DSN dışındaki herkese aşina olduğunuzu düşünüyorum; Bu PDO 'da yeni. Bir DSN, temel olarak PDO'a hangi sürücünün kullanılacağını ve bağlantı ayrıntılarını belirten bir seçenekler dizisidir. Daha fazla başvuru için, kontrol edin PDO MySQL DSN .

$db = new PDO('mysql:Host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

Not: ayrıca charset=UTF-8 kullanabilirsiniz, ancak bazen bir hataya neden olabilir, bu yüzden utf8 kullanmak daha iyidir.

Herhangi bir bağlantı hatası varsa, PDOException ile daha fazla işlenebilecek bir Exception nesnesi atar.

İyi okuma: Bağlantılar ve Bağlantı yönetimi ¶

Dördüncü parametreye bir dizi olarak çeşitli sürücü seçeneklerinden de geçebilirsiniz. PDO parametresini istisna moduna geçiren parametreyi geçirmenizi öneririm. Bazı PDO sürücüleri yerel hazırlanmış ifadeleri desteklemediğinden, PDO hazırlamanın emülasyonunu gerçekleştirir. Ayrıca bu emülasyonu el ile etkinleştirmenize de olanak sağlar. Yerel sunucu tarafı tarafından hazırlanan ifadeleri kullanmak için, açıkça false olarak ayarlamalısınız.

Diğeri, varsayılan olarak MySQL sürücüsünde etkinleştirilmiş emülasyon hazırlamayı kapatmaktır, ancak PDO güvenli bir şekilde kullanılacak şekilde emülasyon hazırlığı kapatılmalıdır.

Daha sonra neden emülasyon hazırlamanın kapatılması gerektiğini açıklayacağım. Sebebini bulmak için lütfen kontrol edin bu yazı .

Tavsiye edilmeyen eski bir MySQL sürümü kullanıyorsanız kullanılabilir.

Aşağıda nasıl yapabileceğinize bir örnek verilmiştir:

$db = new PDO('mysql:Host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password',
              array(PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

PDO inşaatı sonrası özellikleri ayarlayabilir miyiz?

Evet, PDO yapısından sonra setAttribute yöntemiyle bazı özellikler de ayarlayabiliriz:

$db = new PDO('mysql:Host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Hata işleme


Hata işleme PDO içinde mysql_* öğesinden çok daha kolaydır.

mysql_* kullanılırken yaygın bir uygulama:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die(), hatayı ele almak için iyi bir yol değildir, çünkü die içindeki şeyi işleyemiyoruz. Sadece betiği aniden sonlandırır ve hatayı genellikle son kullanıcılarınıza göstermek istemediğiniz ekrana eko yapar ve kanlı bilgisayar korsanlarının şemanızı keşfetmesine izin verir. Alternatif olarak, mysql_* işlevlerinin dönüş değerleri genellikle hataları işlemek için mysql_error () ile birlikte kullanılabilir.

PDO daha iyi bir çözüm sunar: istisnalar. PDO ile yaptığımız her şey bir try-catch bloğuna sarılmalıdır. Hata modu özelliğini ayarlayarak PDO öğesini üç hata modundan birine zorlayabiliriz. Üç hata işleme modu aşağıdadır.

  • PDO::ERRMODE_SILENT. Sadece hata kodlarını ayarlamak ve hemen hemen her sonucu kontrol etmeniz ve ardından hata ayrıntılarını almak için $db->errorInfo(); dosyasına bakmanız gereken mysql_* ile aynı şekilde hareket ediyor.
  • PDO::ERRMODE_WARNINGE_WARNING yükseltin. (Çalışma zamanı uyarıları (önemli olmayan hatalar). Komut dosyasının yürütülmesi durdurulmadı.)
  • PDO::ERRMODE_EXCEPTION: İstisnaları at. PDO tarafından oluşturulan bir hatayı temsil eder. Kendi kodundan bir PDOException atmamalısın. PHP'deki istisnalar hakkında daha fazla bilgi için İstisnalar bölümüne bakınız. Yakalanmadığı zaman or die(mysql_error()); gibi davranır. Ancak or die()'dan farklı olarak, PDOException, seçerseniz, zarif bir şekilde yakalanabilir ve kullanılabilir.

İyi okuma:

Sevmek:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

Ve aşağıdaki gibi try-catch içine sarabilirsiniz:

try {
    //Connect as appropriate as above
    $db->query('hi'); //Invalid query!
} 
catch (PDOException $ex) {
    echo "An Error occured!"; //User friendly message/message you want to show to user
    some_logging_function($ex->getMessage());
}

Şu anda try-catch ile uğraşmanıza gerek yok. İstediğiniz zaman yakalayabilirsiniz, ancak try-catch kullanmanızı öneririz. Ayrıca PDO sayfalarını çağıran işlevin dışında yakalamak daha mantıklı olabilir:

function data_fun($db) {
    $stmt = $db->query("SELECT * FROM table");
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
    data_fun($db);
}
catch(PDOException $ex) {
    //Here you can handle error and show message/perform action you want.
}

Ayrıca, or die() işlevini kaldırabilirsiniz ya da mysql_* gibi diyebiliriz, ancak gerçekten değişecektir. Üretimdeki tehlikeli hata mesajlarını display_errors off düğmesini çevirerek ve sadece hata günlüğünüzü okuyarak gizleyebilirsiniz.

Şimdi, yukarıdaki tüm şeyleri okuduktan sonra, muhtemelen şunu düşünüyorsunuz: basitçe eğilmeye başlamak istediğimde, SELECT, INSERT, UPDATE veya DELETE ifadeleri ne olur? Endişelenme, işte başlıyoruz:


Veri Seçme

PDO select image

Yani mysql_* içinde ne yapıyorsunuz:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
    echo $row['field1'];
}

Şimdi PDO içinde, bunu şöyle yapabilirsiniz:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['field1'];
}

Veya

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

Not: Aşağıdaki yöntemi kullanıyorsanız (query()), bu yöntem bir PDOStatement nesnesini döndürür. Yani sonucu almak istiyorsanız, yukarıdaki gibi kullanın.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
    echo $row['field1'];
}

PDO Verilerinde, deyim işlemcinizin bir yöntemi olan ->fetch() aracılığıyla elde edilir. Getirmeyi aramadan önce, en iyi yaklaşım PDO'ya verilerin nasıl alınmasını istediğinizi söylemektir. Aşağıdaki bölümde bunu açıklıyorum.

Mod Al

Yukarıdaki fetch() ve fetchAll() kodlarında PDO::FETCH_ASSOC kullanımına dikkat edin. Bu, PDO'e, satırları alan adlarıyla birlikte anahtar dizisi olarak döndürmesini söyler. Tek tek anlatacağım birçok alma modu da var.

Her şeyden önce, getirme modunun nasıl seçileceğini açıklarım:

 $stmt->fetch(PDO::FETCH_ASSOC)

Yukarıdakilerde fetch() kullanıyorum. Ayrıca kullanabilirsin:

Şimdi getirme moduna geldim:

  • PDO::FETCH_ASSOC: sonuç kümenizde döndürüldüğü gibi sütun adına göre dizine alınmış bir dizi döndürür
  • PDO::FETCH_BOTH (varsayılan): Sonuç kümenizde döndürülen sütun adı ve 0 dizinli sütun numarası ile dizine alınmış bir dizi döndürür

Daha da fazla seçenek var! Hepsi hakkında okuyun PDOStatement Dokümanları al. .

Satır sayısını almak:

Döndürülen satır sayısını almak için mysql_num_rows kullanmak yerine, bir PDOStatement alabilir ve rowCount() işlevini kullanabilirsiniz:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

Son Eklenen Kimliğin Alınması

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

İfadeleri Ekleme ve Güncelleme veya Silme

Insert and update PDO image

mysql_* işlevinde yaptığımız şey:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

Ve pdo'da, bu aynı şey tarafından da yapılabilir:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

Yukarıdaki sorguda PDO::exec bir SQL deyimini yürütün ve etkilenen satır sayısını döndürür.

Ekle ve sil daha sonra ele alınacaktır.

Yukarıdaki yöntem yalnızca sorguda değişken kullanmadığınızda yararlıdır. Ancak bir sorguda bir değişken kullanmanız gerektiğinde, asla yukarıdaki gibi denemeyin - hazırlanmış deyim veya parametreli ifade is.


Hazırlanan Tablolar

Q. Hazırlanan bir ifade nedir ve neden onlara ihtiyacım var?
A. Hazırlanan ifade, sunucuya yalnızca verileri göndererek birden çok kez çalıştırılabilen önceden derlenmiş bir SQL ifadesidir.

Hazırlanan bir cümle kullanmanın tipik iş akışı şu şekildedir ( Wikipedia 3'ten alıntı ):

  1. Hazırla: İfade şablonu, uygulama tarafından oluşturulur ve veritabanı yönetim sistemine (DBMS) gönderilir. Belirli değerler, parametreler, yer tutucular veya bağlama değişkenleri adı verilen belirtilmemiş olarak bırakılır (aşağıda ? olarak etiketlenmiştir):

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. DBMS, ifade şablonunda sorgu optimizasyonunu ayrıştırır, derler ve gerçekleştirir ve sonucu çalıştırmadan saklar.

  3. Yürüt: Daha sonra, uygulama parametreler için değerler sağlar (veya bağlar) ve DBMS ifadeyi çalıştırır (muhtemelen bir sonuç döndürür). Uygulama, ifadeyi farklı değerlerle istediği kadar çalıştırabilir. Bu örnekte, ilk parametre için 'Ekmek' ve ikinci parametre için 1.00 sağlayabilir.

SQL'inize yer tutucuları dahil ederek hazırlanmış bir ifadeyi kullanabilirsiniz. Temel olarak üç tane yer tutucusu var (bunu bir üstündeki değişkenle denemeyin), biri adsız yer tutucularla, diğeri ad verilmiş yer tutucularla.

Q. Öyleyse şimdi yer tutuculara ne ad verilir ve bunları nasıl kullanırım?
A. Adlandırılmış yer tutucuları. Soru işaretleri yerine, önce iki nokta üst üste gelen açıklayıcı isimler kullanın. İsim sahibinde pozisyon/değer sırasını umursamıyoruz:

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

Ayrıca bir execute array kullanarak da bağlanabilirsiniz:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

OOP arkadaşları için bir başka Nice özelliği, adlandırılmış yer tutucuların, özelliklerin adlandırılmış alanlarla eşleştiğini varsaymak suretiyle doğrudan veritabanınıza nesneler ekleme yeteneğine sahip olmasıdır. Örneğin:

class person {
    public $name;
    public $add;
    function __construct($a,$b) {
        $this->name = $a;
        $this->add = $b;
    }

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

Q. Öyleyse, şimdi adsız yer tutucular nedir ve bunları nasıl kullanırım?
A. Bir örnek verelim:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

ve

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

Yukarıda, bir ad yer tutucusu gibi bir ad yerine bu ? öğelerini görebilirsiniz. Şimdi ilk örnekte, değişkenleri çeşitli yer tutuculara atarız ($stmt->bindValue(1, $name, PDO::PARAM_STR);). Ardından, bu yer tutuculara değer atar ve ifadeyi çalıştırırız. İkinci örnekte, ilk dizi elemanı birinci ?'ye, ikincisi ikinci ?'ye gider.

NOT: adsız yer tutucular içinde, dizideki öğelerin PDOStatement::execute() yöntemine ilettiğimiz sıradaki sırasına dikkat etmeliyiz.


SELECT, INSERT, UPDATE, DELETE hazırlanan sorgular

  1. SELECT:

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
  2. INSERT:

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
    
  3. DELETE:

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
    
  4. UPDATE:

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();
    

NOT:

Ancak PDO ve/veya MySQLi tamamen güvenli değildir. Cevabını kontrol et PDO tarafından hazırlanan ifadeler, SQL enjeksiyonunu önlemek için yeterli mi? - ircmaxell . Ayrıca, cevabından bir kısmını alıntı yapıyorum:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));
1243
NullPoiиteя

İlk önce, herkese verdiğimiz standart yorum ile başlayalım:

Lütfen, mysql_* işlevlerini yeni kodda kullanmayın Artık korunmazlar ve resmen kullanımdan kaldırılmıştır . Bkz. Kırmızı kutu) ? Hazırlanan ifadeler hakkında bilgi edinin ve bunun yerine PDO veya MySQLi - bu makale / karar vermenize yardımcı olacak) kullanın. PDO'yu seçerseniz, işte iyi bir öğretici .

Bunu, cümleyi cümle ile gözden geçirip açıklayalım:

  • Artık korunmuyorlar ve resmen kullanımdan kaldırıldılar

    Bu, PHP topluluğunun bu çok eski işlevler için kademeli olarak destek bıraktığı anlamına geliyor. PHP'nin gelecekteki (yeni) bir sürümünde bulunmamaları muhtemeldir! Bu işlevlerin sürekli kullanımı, (çok) ileriki bir zamanda kodunuzu bozabilir.

    NEW! - ext/mysql şimdiresmen PHP 5.5!

    Daha yeni! ext/mysqlPHP 7içinde kaldırıldı.

  • Bunun yerine hazırlanmış ifadeleri öğrenmelisiniz

    mysql_* uzantısı, hazırlanan ifadeler 'i desteklemez; bu, (diğer şeylerin yanı sıra) SQL Injection' e karşı çok etkili bir önlemdir. MySQL'e bağlı uygulamalarda, saldırganların betiğinize erişmesini ve veritabanınızda olası bir sorg işlemi gerçekleştirmesini sağlayan çok ciddi bir güvenlik açığı düzeltildi.

    Daha fazla bilgi için, bkz. PHP'de SQL enjeksiyonunu nasıl önleyebilirim?

  • Kırmızı Kutuya Bakın?

    Herhangi bir mysql işlevi el kitabına gittiğinizde, artık kullanılmaması gerektiğini açıklayan kırmızı bir kutu görürsünüz.

  • PDO veya MySQLi kullanın

    Daha iyi, daha sağlam ve sağlam alternatifler var, PDO - PHP Veritabanı Nesnesi, bu da veritabanı etkileşimine eksiksiz bir OOP yaklaşımı sunar, ve MySQLi, ki bu MySQL'e özgü bir gelişmedir.

292
Madara Uchiha

Kullanım kolaylığı

Analitik ve sentetik sebepler çoktan bahsedilmişti. Yeni gelenler için, tarihli mysql_ işlevlerini kullanmayı bırakma konusunda daha önemli bir teşvik var.

Çağdaş veritabanı API'leri sadece daha kolay kullanmak içindir.

Çoğunlukla sınır parametreleri olan kodu basitleştirebilir. Ve mükemmel öğreticiler (yukarıda görüldüğü gibi) ile PDO 'a geçiş çok zor değildir.

Bir seferde daha büyük bir kod tabanının yeniden yazılması zaman alır. Bu ara alternatif için Raison d'être:

Eşdeğer pdo_ * yerine mysql_ *

< pdo_mysql.php > kullanarak eski mysql_ işlevlerinden minimal çaba ile geçiş yapabilirsiniz. _pdo__ meslektaşlarının yerine _mysql__ işlev sarmalayıcıları ekler.

  1. Basitçe _include_once(_ "pdo_mysql.php" _);_ ile veritabanı ile etkileşime girmek zorunda kalan her bir komut dosyasında.

  2. Kaldır _mysql__ fonksiyon öneki her yerde ve onu pdo_ ile değiştirin.

    • _mysql__connect() olur _pdo__connect()
    • _mysql__query() olur _pdo__query()
    • _mysql__num_rows() olur _pdo__num_rows()
    • _mysql__insert_id() olur _pdo__insert_id()
    • _mysql__fetch_array() olur _pdo__fetch_array()
    • _mysql__fetch_assoc() olur _pdo__fetch_assoc()
    • _mysql__real_escape_string() olur _pdo__real_escape_string()
    • ve diğerleri ...

  3. Kodunuz aynı şekilde çalışacak ve hala aynı görünüyor:

    _include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }
    _

Et voilà.
Kodunuz kullanarak PDO’dur.
Şimdi gerçekte faydalanma zamanı geldi.

Bağlı parametrelerin kullanımı kolay olabilir

Sadece daha az hantal bir API'ye ihtiyacınız var.

pdo_query(), ilişkili parametreler için çok kolay destek ekler. Eski kodu dönüştürme basittir:

Değişkenlerinizi SQL dizesinin dışına taşıyın.

  • Bunları virgülle ayrılmış işlev parametreleri olarak pdo_query() dosyasına ekleyin.
  • Soru işaretlerini _?_ değişkenlerin önceden olduğu yer tutucular olarak yerleştirin.
  • Daha önce dize değerleri/değişkenleri içine alan _'_ tek tırnaklarından kurtulun.

Avantaj, uzun kod için daha belirgin hale gelir.

Genellikle dize değişkenleri sadece SQL'e dahil değildir, aynı zamanda aradaki kaçan çağrılarla birleştirilir.

_pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")
_

_?_ yer tutucuları uygulanmış durumdayken bununla uğraşmanıza gerek yok:

_pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)
_

Unutmayın ki pdo_ * hala izin verir ya da.
Sadece bir değişkenden kaçmayın ve aynı sorguya bağlayın.

  • Yer tutucu özelliği, arkasındaki gerçek PDO tarafından sağlanır.
  • Böylece daha sonra _:named_ yer tutucu listesine izin verildi.

Daha da önemlisi, herhangi bir sorgunun arkasına $ _REQUEST [] değişkenlerini güvenle iletebilirsiniz. _<form>_ alanları gönderildiğinde, veritabanı yapısına tam olarak eşleştiği zaman:

_pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
_

Çok fazla basitlik. Fakat neden yeniden yazmak isteyebileceğinize dair bazı öneriler ve teknik nedenlerle geri dönelim _mysql__ ve kaçış.

Herhangi bir oldschool'i düzeltin veya kaldırın sanitize() işlev

Hepsini değiştirdikten sonra _mysql__ bağlı params ile _pdo_query_ çağrıları, tüm gereksiz _pdo_real_escape_string_ çağrılarını kaldırın.

Özellikle, herhangi bir biçimde veya başka şekillerde tarih öğreticileri tarafından ilan edilen sanitize veya clean veya filterThis veya _clean_data_ işlevlerini düzeltmelisiniz:

_function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}
_

Buradaki göze batan hata ise dokümantasyon eksikliği. Daha da önemlisi, filtreleme sırası tamamen yanlış sıradaydı.

  • Doğru sipariş şu şekilde olurdu: en içteki çağrı olarak gizlice stripslashes, ardından en son çağrı olarak trim, daha sonra _strip_tags_, çıktı bağlamında htmlentities ve son olarak da __escape_string_ Uygulaması, doğrudan SQL interparsing'in öncülüğünü yapmalıdır.

  • Ancak ilk adım olarak sadece _real_escape_string çağrısından kurtulun.

  • Veritabanınız ve uygulama akışınız HTML bağlamında güvenli dizeler bekliyorsa, şimdilik sanitize() işlevinizin geri kalanını saklamanız gerekebilir. Yalnızca bundan sonra kaçan HTML'yi uyguladığına dair bir yorum ekleyin.

  • Dize/değer işleme, PDO'ya ve onun parametreleştirilmiş ifadelerine verilmiştir.

  • Dezenfekte fonksiyonunuzda stripslashes()'dan herhangi bir söz edilebilirse, daha yüksek düzeyde bir gözetim belirtebilir.

    • Yaygın olarak kullanımdan kaldırılan magic_quotes hasardan (çifte kaçış) kurtulmak için yaygın olarak bulunuyordum. Ancak hangisi en iyi merkezi olarak sabitlenir , dizeye göre değil.

    • serland reversal yaklaşımlarından birini kullanın. Ardından sanitize işlevindeki stripslashes() öğesini kaldırın.

    magic_quotes hakkındaki tarihi not. Bu özellik doğru şekilde kullanımdan kaldırılmıştır. Ancak hatalı olarak başarısız olarak gösterildi --- güvenlik özelliği. Ancak magic_quotes, tenis topları beslenme kaynağı olarak başarısız olduğu kadar başarısız bir güvenlik özelliğidir. Bu sadece onların amacı değildi.

    PHP2/FI'daki orijinal uygulama açıkça "tırnak işaretleri otomatik olarak kaldırılacak ve form verilerinin doğrudan msql sorgularına iletilmesini kolaylaştıracak" ifadesiyle tanıtıldı. Özellikle, yalnızca ASCII destekli olduğu için mSQL ile kullanmak yanlışlıkla güvenliydi.
    Ardından PHP3/Zend, MySQL için magic_quotes öğesini yeniden sunmuş ve yanlış belgelendirmiştir. Ama aslında sadece bir kolaylık özelliği idi, güvenlik amaçlı değildi.

Hazırlanan ifadeler nasıl farklılık gösterir?

Dize değişkenlerini SQL sorgularına karıştırdığınızda, takip etmeniz daha karmaşık olmaz. Aynı zamanda MySQL'in kodu ve verileri tekrar ayırması için de büyük bir çaba.

SQL enjeksiyonları basitçe veri kod içine akıyor bağlamındadır. Bir veritabanı sunucusu daha sonra PHP sorgu değişkenleri arasındaki başlangıçta değişkenleri nereye yapıştırdığını fark edemez.

İlişkili parametrelerle, PHP kodunuzda SQL kodunu ve SQL bağlamı değerlerini ayırırsınız. Ancak sahnelerin arkasına tekrar karıştırılmıyor (PDO :: EMULATE_PREPARES hariç). Veritabanınız değişmemiş SQL komutlarını ve 1: 1 değişken değerlerini alır.

Bu cevap, bırakmanın okunabilirlik avantajlarına dikkat etmeniz gerektiğini vurgularken _mysql__. Bu görünür ve teknik veri/kod ayrımı nedeniyle zaman zaman bir performans avantajı da vardır (sadece farklı değerlere sahip tekrarlanan INSERT'ler).

Parametre bağlanmasının hala all SQL enjeksiyonlarına karşı sihirli bir one-stop çözümü olmadığını unutmayın. Veri/değerler için en yaygın kullanımı gerçekleştirir. Ancak sütun adını/tablo tanımlayıcılarını beyaz listeye alamaz, dinamik yan tümce yapımında yardımcı olabilir veya yalnızca düz dizi değer listelerini kullanamazsınız.

Hibrit PDO kullanımı

Bu _pdo_*_ sarıcı işlevleri, kodlama dostu bir duruş açığı API'si oluşturur. (Eğer kendi kendine özgü işlev imza kayması için olmasaydı, MYSQLI olabilirdi. Ayrıca çoğu zaman gerçek PDO'ları ortaya çıkarırlar.
Yeniden yazmanın yeni pdo_ işlev adlarını kullanmayı bırakması gerekmez. Her pdo_query () 'yi düz bir $ pdo-> prepare () -> execute () çağrısına tek tek geçiş yapabilirsiniz.

Yine de basitleştirmeye başlamak en iyisidir. Örneğin, ortak sonuç alma:

_$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {
_

Sadece bir foreach yineleme ile değiştirilebilir:

_foreach ($result as $row) {
_

Veya daha iyisi, doğrudan ve eksiksiz bir dizi alımı:

_$result->fetchAll();
_

Çoğu durumda, PDO veya mysql_'nin genellikle başarısız sorgulardan sonra sağlamasından daha fazla yardımcı uyarılar elde edersiniz.

Diğer seçenekler

Yani bu umarım bazı pratik nedenleri ve bırakılması gereken değerli bir yolu görselleştirdi. _mysql__.

Sadece pdo 'ya geçmek oldukça kesin değil. pdo_query() ayrıca onun üzerine sadece bir ön uç.

Ayrıca parametre bağlama özelliğini tanıtmazsanız veya daha hoş API'den başka bir şey kullanabilirseniz, bu anlamsız bir anahtardır. İnşallah yeni gelenlere karşı cesaret kırıcılığını ilerletmeyecek kadar basit. (Eğitim genellikle yasaklardan daha iyi çalışır.)

İşe yarayabilecek en basit şey için uygun olmasına rağmen, yine de çok deneysel bir koddur. Sadece haftasonu yazdım. Ancak bir sürü alternatif var. Sadece google PHP veritabanı soyutlama ve biraz göz atın. Bu tür görevler için her zaman birçok mükemmel kitaplık olmuştur ve olacaktır.

Eğer veritabanı etkileşiminizi daha da basitleştirmek istiyorsanız, Paris/Idiorm gibi eşleştiriciler denemeye değer. Tıpkı hiç kimse JavaScript’de mülayim DOM kullanmıyor gibi, bugünlerde bir ham veritabanı arayüzüne bakmanıza gerek yok.

212
mario

mysql_ işlevleri:

  1. güncel değiller - daha fazla korunmuyorlar
  2. kolayca başka bir veritabanı arka ucuna gitmenize izin verme
  3. hazırlanan ifadeleri desteklemediğinden,
  4. programcıları, sorgu oluşturmak için birleştirme kullanmaya teşvik ederek SQL enjeksiyon güvenlik açıklarına neden olabilir
136
Alnitak

teknik sebeplerden bahsetmişken, sadece çok az, çok spesifik ve nadiren kullanılan bazı sebepler var. Büyük olasılıkla onları hayatında asla kullanmayacaksın.
Belki de çok cahilimdir, ama onları gibi şeyleri kullanma fırsatım olmadı

  • engellenmeyen, zaman uyumsuz sorgular
  • çoklu sonuç kümelerini döndüren saklı yordamlar
  • Şifreleme (SSL)
  • Sıkıştırma

İhtiyacınız olursa - bunlar şüphesiz ki, mysql uzantısından daha şık ve modern görünümlü bir şeye geçmenin teknik nedenleridir.

Bununla birlikte, deneyiminizi biraz daha zorlaştıracak teknik olmayan bazı sorunlar da vardır

  • bu işlevlerin modern PHP sürümleriyle daha fazla kullanılması, kullanımdan kaldırılmış bildirimleri artıracaktır. Onlar sadece kapatılabilir.
  • uzak bir gelecekte, varsayılan PHP yapısından kaldırılabilirler. Çok fazla bir şey değil, çünkü mydsql ext PECL'e taşınacak ve sitelerden on yıllardır çalışan müşterilerini kaybetmek istemedikleri için her barınak PHP ile derlenmekten mutlu olacak.
  • stackoverflow topluluğundan güçlü direnç. Her zaman bu dürüst işlevlerden bahsettiniz, size sıkı bir tabu altında oldukları söylendi.
  • ortalama bir PHP kullanıcısı olması nedeniyle, bu işlevleri kullanma fikriniz büyük olasılıkla hataya açık ve yanlıştır. Sadece sana yanlış yolu öğreten tüm bu sayısız öğretici ve el kitabından dolayı. Fonksiyonların kendileri değil - vurgulamak zorundayım - ama kullanma biçimleri.

Bu ikinci sorun bir sorundur.
Fakat bence önerilen çözüm de daha iyi değil.
Bana öyle geliyor ki too idealistic , tüm bu PHP kullanıcılarının SQL sorgularını bir kerede nasıl düzgün bir şekilde idare edeceğini öğrenecekleri bir rüya. Büyük olasılıkla onlar sadece mysql_ * 'ı mysqli_ *' a değiştireceklerdi. Mekanik olarak aynı yaklaşımı bırakarak . Özellikle mysqli hazırlanan ifadeler kullanması inanılmaz acılı ve zahmetli bir kullanım sağlar.
yerli hazırlanan ifadeleri 'ın SQL enjeksiyonlarından korumak için yeterli olmadığını ve ne mysqli’yi koruyacağından bahsetmiyorum. PDO bir çözüm sunuyor.

Bu nedenle, bu dürüst uzantıyla mücadele etmek yerine, yanlış uygulamalarla savaşmayı ve insanları doğru şekilde eğitmeyi tercih ederim.

Ayrıca, gibi bazı yanlış veya önemli olmayan nedenler de var.

  • Saklı İşlemleri desteklemiyor (yaş için mysql_query("CALL my_proc"); kullanıyorduk)
  • İşlemleri desteklemiyor (yukarıdakiyle aynı)
  • Çoklu İfadeleri desteklemiyor (kime ihtiyaç duyar?)
  • Aktif gelişme altında değil (peki? Bu ne? sizi pratik bir şekilde etkiler mi?)
  • OO arayüzü yoksundur (bir tane oluşturmak birkaç saat meselesidir)
  • Hazırlanan İfadeleri veya Parametrelenmiş Sorguları desteklemiyor

Sonuncusu ilginç bir nokta. Mysql ext yerel hazırlanmış ifadeleri desteklemese de, güvenlik için gerekli değildir. Elle yapılan yer tutucuları kullanarak hazırlanmış ifadeleri kolayca sahte yapabiliriz (PDO'nun yaptığı gibi):

function paraQuery()
{
    $args  = func_get_args();
    $query = array_shift($args);
    $query = str_replace("%s","'%s'",$query); 

    foreach ($args as $key => $val)
    {
        $args[$key] = mysql_real_escape_string($val);
    }

    $query  = vsprintf($query, $args);
    $result = mysql_query($query);
    if (!$result)
    {
        throw new Exception(mysql_error()." [$query]");
    }
    return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

voila , her şey parametreli ve güvenlidir.

Ama tamam, kılavuzdaki kırmızı kutuyu beğenmiyorsanız, bir seçim sorunu ortaya çıkar: mysqli veya PDO?

Eh, cevap aşağıdaki gibi olurdu:

  • Bir veritabanı soyutlama katmanı kullanmanın ve bir tane oluşturmak için bir API aramanın gerekliliğini anlıyorsanız, mysqli çok iyi bir seçimdir , gerçekten de mysql'e özgü birçok özelliği destekliyor.
  • PHP milletinin büyük çoğunluğu gibi, uygulama kodunda ham API çağrıları kullanıyorsunuz (temelde yanlış olan uygulama) - PDO tek seçenek , Bu uzantı sadece API değil, yarı-DAL gibi görünüyor, hala eksik ama birçok önemli özellik sunuyor, çünkü ikisi PDO'yu mysqli'den eleştirel olarak ayırıyor:

    • mysqli'den farklı olarak, PDO yer tutucuları değere göre bağlayabilir ve bu da dinamik olarak oluşturulan sorguları oldukça karışık kodlu birkaç ekran olmadan gerçekleştirilebilir hale getirir.
    • mysqli'den farklı olarak, PDO her zamanki basit bir dizide sorgu sonucunu her zaman döndürürken, mysqli bunu sadece mysqlnd kurulumlarında yapabilir.

Öyleyse, ortalama bir PHP kullanıcısıysanız ve yerel hazırlanmış ifadeleri kullanırken kendinize bir ton sıkıntıdan kurtulmak istiyorsanız, PDO - tekrar - tek seçenek.
Bununla birlikte, PDO da bir gümüş mermi değildir ve zorlukları vardır.
Böylece, PDO etiketi wiki içindeki tüm genel tuzaklar ve karmaşık durumlar için çözümler yazdım.

Bununla birlikte, uzantılardan bahseden herkes daima Mysqli ve PDO hakkında 2 önemli gerçekler eksik:

  1. Hazırlanan deyim , gümüş bir madde işareti değildir . Hazırlanan ifadeler kullanılarak bağlanamayan dinamik tanımlayıcılar vardır. Sorgu oluşturmayı zor bir görev yapan, bilinmeyen sayıda parametreye sahip dinamik sorgular vardır.

  2. Ne mysqli_ * ne de PDO işlevleri uygulama kodunda görünmelidir.
    Bunlar ve uygulama kodu arasında, tüm kirli ciltleme, döngü, hata yönetimi vb. İşlerini yapan uygulama kodu arasında bir soyutlama katmanı olması gerekir. uygulama kodu DRY ve temiz. Özellikle dinamik sorgu oluşturma gibi karmaşık durumlar için.

Yani, sadece PDO veya mysqli'ye geçmek yeterli değildir. Birinin bir ORM veya bir sorgu oluşturucu veya kodlarında ham API işlevlerini çağırmak yerine herhangi bir veritabanı soyutlama sınıfı kullanması gerekir.
Ve aksine - uygulama kodunuzla mysql API'niz arasında bir soyutlama katmanınız varsa - aslında hangi motorun kullanıldığı önemli değil. mysql ext kullanabilirsiniz kullanımdan kaldırılana kadar ve soyutlama sınıfınızı kolayca başka bir motora yeniden yazın, tüm uygulama kodları eksiksiz.

İşte böyle bir soyutlama sınıfının nasıl olması gerektiğini göstermek için safemysql sınıf 'a dayanan bazı örnekler:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

Bu tek bir satırı PDO ile ihtiyacınız olan kod miktarı ile karşılaştırın.
Ardından çılgın kod miktarı ile karşılaştırın, ham Mysqli'nin hazırladığı ifadelerle ihtiyacınız olacak. Hata işleme, profil oluşturma, sorgu günlüğünün zaten yerleşik ve çalışıyor olduğunu unutmayın.

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

Her bir alan adı altı ila on kez tekrarlandığında - bu çok sayıda adlandırılmış yer tutucu, ciltleme ve sorgu tanımlarında, normal PDO uçlarıyla karşılaştırın.

Başka bir örnek:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

Böyle pratik bir durumla başa çıkmak için PDO'ya bir örnek bulmak zor.
Ve çok endişeli ve büyük olasılıkla güvensiz olacak.

Bu yüzden, bir kez daha - sadece ham sürücü değil, yalnızca başlangıç ​​el kitabındaki saçma örnekler için değil, gerçek hayattaki problemleri çözmede faydalı olan sizin endişeniz değil, soyutlama sınıfınız olmalıdır.

104

Pek çok neden var, ama belki de en önemlisi, bu fonksiyonların güvenli olmayan programlama uygulamalarını teşvik etmeleridir, çünkü hazırlanan ifadeleri desteklememektedir. Hazırlanan ifadeler, SQL enjeksiyon saldırılarını önlemeye yardımcı olur.

mysql_* işlevlerini kullanırken, kullanıcı tarafından sağlanan parametreleri mysql_real_escape_string() üzerinden çalıştırmayı hatırlamanız gerekir. Yalnızca bir yerde unutursanız veya girişin yalnızca bir bölümünden kaçarsanız, veritabanınız saldırıya maruz kalabilir.

Hazırlanan ifadeleri PDO veya mysqli içinde kullanmak, bu tür programlama hatalarının yapılmasını zorlaştıracaktır.

88
Trott

Çünkü (diğer nedenlerin yanı sıra), girdi verilerinin sterilize edilmesini sağlamak çok daha zor. Parametreli sorgular kullanıyorsanız, biri PDO veya mysqli'de olduğu gibi, riski tamamen önleyebilirsiniz.

Örnek olarak, birisi kullanıcı adı olarak "enhzflep); drop table users" öğesini kullanabilir. Eski işlevler, sorgu başına birden fazla ifade çalıştırılmasına izin verecek, böylece kötü bir böcek gibi bir tablonun tamamını silebilir.

Eğer biri mysqli'nin PDO'sunu kullanacak olsaydı, kullanıcı ismi "enhzflep); drop table users" olur.

Bkz. Bobby-tables.com .

71
enhzflep

Bu cevap, zayıf yazılmış PHP kullanıcı doğrulama kodunu atlamanın ne kadar önemsiz olduğunu, bu saldırıların nasıl (ve neyin kullanıldığını) ve eski MySQL işlevlerinin güvenli bir şekilde hazırlanmış bir ifadeyle nasıl değiştirileceğini göstermek için yazılmıştır. , neden StackOverflow kullanıcıları (muhtemelen çok sayıda rep ile) kodlarını iyileştirmek için sorular soran yeni kullanıcılara güveniyorlar.

Öncelikle, lütfen bu testi mysql veritabanı oluşturmaktan çekinmeyin (benimki hazırlığı olarak adlandırdım):

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

Bu işlemle PHP kodumuza geçebiliriz.

Aşağıdaki komut dosyasının bir web sitesindeki yönetici için doğrulama işlemi olduğunu varsayalım (basitleştirilmiş ancak test için kopyalayıp kullanıyorsanız çalışır):

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

İlk bakışta yeterince okunaklı görünüyor.

Kullanıcı bir kullanıcı adı ve şifre girmek zorunda değil mi?

Parlak, aşağıya girmeyin:

user: bob
pass: somePass

ve gönderin.

Çıktı aşağıdaki gibidir:

You could not be verified. Please try again...

Süper! Beklendiği gibi çalışıyor, şimdi gerçek kullanıcı adı ve şifreyi deneyelim:

user: Fluffeh
pass: mypass

Şaşırtıcı! Hi-fives her yerde, kod doğru bir yönetici doğruladı. Mükemmel!

Eh, tam olarak değil. Diyelim ki kullanıcı zeki küçük bir insan. Diyelim ki kişi benim.

Aşağıdakileri girin:

user: bob
pass: n' or 1=1 or 'm=m

Ve çıktı:

The check passed. We have a verified admin!

Tebrikler, süper korumalı yöneticilerinize yalnızca yanlış bir kullanıcı adı ve yanlış bir şifre girmem için girmeme izin verdiniz. Cidden, bana inanmıyorsanız, sağladığım kodla veritabanını oluşturun ve bu PHP kodunu çalıştırın; bu, GERÇEKTEN, kullanıcı adını ve parolayı gayet güzel bir şekilde doğruladı.

Öyleyse, cevaben, NEDEN BAĞLIYINIZ IS.

Öyleyse, neyin yanlış gittiğini ve neden sadece süper-yönetici-yarasa mağarasına girdiğime bir bakalım. Bir tahminde bulundum ve girdilerinize dikkat etmediğinizi varsaydım ve doğrudan veritabanına aktardım. Girdiyi, gerçekte çalıştırmakta olduğunuz sorguyu DEĞİŞTİRECEK şekilde yapılandırdım. Öyleyse, olması gereken neydi ve sonunda ne oldu?

select id, userid, pass from users where userid='$user' and pass='$pass'

Sorgu bu, ancak değişkenleri kullandığımız asıl girdilerle değiştirdiğimizde, aşağıdakileri elde ediyoruz:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

"Parolamı" nasıl oluşturduğumu görün, böylece önce parolanın etrafındaki tek teklifi kapatıp ardından tamamen yeni bir karşılaştırma yapalım mı? Sonra sadece güvenlik için, başka bir "string" ekledim, böylece tek alıntı orijinal olarak aldığımız kodda beklendiği gibi kapanacaktı.

Ancak bu, şu anda size bağıran insanlarla ilgili değil, kodunuzu nasıl daha güvenli hale getireceğinizi göstermekle ilgili.

Tamam, peki yanlış giden neydi ve nasıl düzeltebiliriz?

Bu klasik bir SQL enjeksiyon saldırısı. Bu konuda en basitlerinden biri. Saldırı vektörleri ölçeğinde bu, bir tanka saldıran ve kazanan bir bebek.

Peki, kutsal yönetici bölümünüzü nasıl koruyacağız ve onu Güzel ve güvenli hale getireceğiz? Yapılacak ilk şey, gerçekten eski ve kullanımdan kaldırılmış mysql_* işlevlerini kullanmayı bırakmak olacaktır. Biliyorum, internette bulduğun bir öğreticiyi takip ettin ve işe yarıyor, ama eski, modası geçmiş ve birkaç dakika uzağında, daha yeni terlemiştim.

Şimdi, mysqli_ veya PDO kullanarak daha iyi seçeneklere sahipsiniz. Şahsen ben büyük bir PDO hayranıyım, bu yüzden bu cevabın geri kalanında PDO kullanacağım. Profesyoneller ve aleyhte olanlar var, ama şahsen ben profesyonellerin aleyhte olanlardan daha ağır olduğunu gördüm. Birden fazla veritabanı motorunda taşınabilir - ister MySQL, ister Oracle kullanıyorsunuz, isterse kanlı bir şey olsun - yalnızca bağlantı dizesini değiştirerek, kullanmak istediğimiz tüm fantezi özelliklere sahiptir ve hoş ve temizdir. Temizliği severim.

Şimdi bu koda tekrar bakalım, bu sefer bir PDO nesnesi kullanılarak yazılmış:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:Host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

En büyük farklar, artık mysql_* işlevinin olmamasıdır. Hepsi bir PDO nesnesi üzerinden yapılır, ikincisi, hazırlanmış bir ifade kullanıyor. Şimdi, sorduğun hazır bir ifade nedir? Bir sorguyu çalıştırmadan önce veritabanına, sorgunun ne olduğunu çalıştıracağımızı söylemenin bir yolu. Bu durumda, veritabanına şunu söyleriz: "Merhaba, kimliği, kullanıcı kimliğini ve kullanıcı kimliğinin değişken olduğu ve kullanıcı kimliğinin de değişken olduğu tablo kullanıcılarından geçmek için bir select deyimi çalıştırıyorum.".

Daha sonra execute deyiminde, veritabanına şimdi beklediği tüm değişkenleri içeren bir dizi iletiriz.

Sonuçlar muhteşem. Bu kullanıcı adı ve şifre kombinasyonlarını daha önce tekrar deneyelim:

user: bob
pass: somePass

Kullanıcı doğrulanmadı. Muhteşem.

Peki ya:

user: Fluffeh
pass: mypass

Oh, biraz heyecanlandım, işe yaradı: Kontrol geçti. Doğrulanmış bir yöneticimiz var!

Şimdi, küçük doğrulama sistemimizi geçmeye çalışmak için akıllı bir bölümün gireceği verileri deneyelim:

user: bob
pass: n' or 1=1 or 'm=m

Bu sefer aşağıdakileri alıyoruz:

You could not be verified. Please try again...

Bu yüzden soru gönderirken bağırıyorsunuz - çünkü insanlar kodunuzun atlanmaya çalışılsa bile atlanabileceğini görebiliyorlar. Lütfen, kodunuzu geliştirmek, daha güvenli hale getirmek ve güncel olan işlevleri kullanmak için bu soruyu ve yanıtı kullanın.Son olarak, bu MÜKEMMEL kod olduğunu söylemek değildir. İyileştirmek için yapabileceğiniz birçok şey var, örneğin şifreli şifreler kullanın, hassas bilgileri veritabanında sakladığınızda, düz metin olarak saklamayın, birden fazla doğrulama seviyesine sahip olun. Sadece eski enjeksiyon eğilimli kodunuzu değiştirirseniz, iyi kod yazma yolunda WELL olacaksınız - ve bu ana kadar okuduğunuz ve hala okuduğunuz gerçeği bana sadece bu tipte bir uygulama yapmamaya dair bir umut veriyor. web sitelerinizi ve uygulamalarınızı yazarken kodun dışına çıkacak, ancak dışarı çıkıp biraz önce bahsettiğim diğer şeyleri araştırabilirsiniz - ve daha fazlası. Zorlukla çalışan en temel kodu değil, yazabileceğiniz en iyi kodu yazın.

Lastly, this isn't to say that this is PERFECT code. There are many more things that you could do to improve it, use hashed passwords for example, ensure that when you store sensetive information in the database, you don't store it in plain text, have multiple levels of verification - but really, if you just change your old injection prone code to this, you will be WELL along the way to writing good code - and the fact that you have gotten this far and are still reading gives me a sense of hope that you will not only implement this type of code when writing your websites and applications, but that you might go out and research those other things I just mentioned - and more. Write the best code you can, not the most basic code that barely functions.

62
Fluffeh

MySQL uzantısı üçünün en eskisidir ve geliştiricilerin MySQL ile iletişim kurmak için kullandıkları orijinal yoldur. Bu uzantı şimdi kullanımdan kaldırıldı diğer ikialternatiflerin lehine hem PHP hem de MySQL'in yeni sürümlerinde yapılan iyileştirmeler nedeniyle.

  • MySQLi , MySQL veritabanlarıyla çalışmak için 'geliştirilmiş' uzantıdır. MySQL sunucusunun daha yeni sürümlerinde bulunan özelliklerden yararlanır, geliştiriciye hem işlev odaklı hem de nesne yönelimli bir arayüz sunar ve birkaç başka güzel şey yapar.

  • PDO , daha önce ana veritabanı erişim uzantıları, örneğin MySQL, PostgreSQL, SQLite, MSSQL, vb. üzerine yayılmış olan işlevselliğin çoğunu birleştiren bir API sunar. veritabanı bağlantılarıyla, sorgular ve sonuç kümeleri ve düşük seviye sürücüler veritabanı sunucusuyla iletişim ve kaynak kullanımı gerçekleştirir. Çok sayıda tartışma ve çalışma PDO'ya giriyor ve modern, profesyonel kodda veritabanlarıyla çalışmanın uygun yöntemi olarak kabul ediliyor.

30
Alexander

Özetlemek gerekirse, yukarıdaki cevapları çok uzun buluyorum:

MySQL uzantısı bir kaç tane vardır. yararları, .__ üzerinde önemli geliştirmeler. mysql uzantısı olmak:

  • Nesneye yönelik arayüz
  • Hazırlanan Tablolara Destek
  • Birden Fazla İfade Desteği
  • İşlemler için destek
  • Gelişmiş hata ayıklama yetenekleri
  • Gömülü sunucu desteği

Kaynak: MySQLi genel bakış


Yukarıdaki cevaplarda açıklandığı gibi, mysql alternatifleri mysqli ve PDO'dur (PHP Data Objects).

  • API, sunucu tarafında Hazırlanan İfadeleri destekler: MYSQLi ve PDO tarafından desteklenir
  • API, müşteri tarafında Hazırlanan İfadeleri destekler: Yalnızca PDO tarafından desteklenir
  • API, Saklı İşlemleri destekler: Hem MySQLi hem de PDO
  • API, Çoklu İfadeleri ve tüm MySQL 4.1+ işlevselliğini destekler - MySQLi ve çoğunlukla PDO tarafından desteklenir

Hem MySQLi hem de PDO PHP 5.0'da tanıtıldı, oysa MySQL PHP 3.0'dan önce tanıtıldı. Unutulmaması gereken nokta, MySQL'in PHP5.x içerisine dahil edilmesine rağmen sonraki sürümlerde kullanımdan kaldırılmış olmasıdır. 

19
Ani Menon

Neredeyse tüm mysql_* işlevlerini mysqli veya PDO kullanarak tanımlamak mümkündür. Onları eski PHP uygulamanızın üstüne eklemeniz yeterlidir ve PHP7'de çalışacaktır. Benim çözümüm here .

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($Host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($Host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($Host, $user, $pass) {
    return mysql_connect($Host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_Host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_Host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}
2
Pavel Tzonkov

Bu mysql_connect(), mysql_query() türüne benzeyen işlevler önceki sürüm PHP i.e (PHP 4) işlevidir ve şu anda kullanımda değildir.

Bunlar PHP'nin son sürümündeki benzer şekilde mysqli_connect(), mysqli_query() ile değiştirilir.

Hatanın arkasındaki sebep budur.

0
Killer

Bu, bugün eski bir sorudur (Ocak 2019), ancak bu hala faydalı olabilir. Yaklaşık 7 yıl önce MySQL/MySQLi/PDO işlevselliğinin tablosal bir haritasını çıkardım. Yararlı bir referans olabilir. Burada burada çevrimiçi ve aşağıda çoğaltılmıştır. HTML'yi kopyalayıp yapıştırmaktan çekinmeyin.

Pratik bir mesele olarak, prosedürel MySQL işlevlerini OOP MySQLi'ye dönüştürmenin en az dirençli yol olduğunu buldum. İki DB bağlantısının aynı anda açık olması son derece iyidir ve bu bize dönüşümler boyunca çalıştığımızda esneklik sağladı - komut dosyalarını her seferinde bir sorgu olarak parça parça bazında dönüştürebilirdik. Bugün bunu tavsiye etmeme rağmen, o zamanlar uygun değildi.

<div class="container">

<h2>Mapping Obsolete MySQL Functions to Current PHP Extensions</h2>
<table>
<tr><th>MySQL Extension</th><th>MySQL<b><i>i</i></b></th><th>PDO</th></tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-affected-rows.php">mysql_affected_rows</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.affected-rows.php">mysqli::$affected_rows</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.rowcount.php">PDOStatement::rowCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-client-encoding.php">mysql_client_encoding</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.character-set-name.php">mysqli::character_set_name</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-close.php">mysql_close</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.close.php">mysqli::close</a></td>
    <td>Assign NULL to PDO Object</td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-connect.php">mysql_connect</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.construct.php">mysqli::__construct</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-create-db.php">mysql_create_db</a></td>
    <td>Query: CREATE DATABASE</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-data-seek.php">mysql_data_seek</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-stmt.data-seek.php">mysqli_stmt::data_seek</a></td>
    <td>PDO::FETCH_ORI_ABS (?)</td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-db-name.php">mysql_db_name</a></td>
    <td>Query: SELECT DATABASE()</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-db-query.php">mysql_db_query</a></td>
    <td> </td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-drop-db.php">mysql_drop_db</a></td>
    <td>Query: DROP DATABASE</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-errno.php">mysql_errno</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.errno.php">mysqli::$errno</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.errorcode.php">PDO::errorCode</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-error.php">mysql_error</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.error-list.php">mysqli::$error_list</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.errorinfo.php">PDO::errorInfo</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-escape-string.php">mysql_escape_string</a></td>
    <td> </td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-array.php">mysql_fetch_array</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-array.php">mysqli_result::fetch_array</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-assoc.php">mysql_fetch_assoc</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-assoc.php">mysqli_result::fetch_assoc</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-field.php">mysql_fetch_field</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field.php">mysqli_result::fetch_field</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-lengths.php">mysql_fetch_lengths</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.lengths.php">mysqli_result::$lengths</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-object.php">mysql_fetch_object</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-object.php">mysqli_result::fetch_object</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-fetch-row.php">mysql_fetch_row</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-row.php">mysqli_result::fetch_row</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-flags.php">mysql_field_flags</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-fields.php">mysqli_result::fetch_fields</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-len.php">mysql_field_len</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-name.php">mysql_field_name</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-seek.php">mysql_field_seek</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.field-seek.php">mysqli_result::field_seek</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetch.php">PDOStatement::fetch</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-table.php">mysql_field_table</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-field-type.php">mysql_field_type</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php">mysqli_result::fetch_field_direct</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.getcolumnmeta.php">PDOStatement::getColumnMeta</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-free-result.php">mysql_free_result</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-result.free.php">mysqli_result::free</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.closecursor.php">PDOStatement::closeCursor</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-client-info.php">mysql_get_client_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-client-info.php">mysqli::get_client_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-Host-info.php">mysql_get_Host_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-Host-info.php">mysqli::$Host_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-proto-info.php">mysql_get_proto_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-proto-info.php">mysqli::$protocol_version</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-get-server-info.php">mysql_get_server_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.get-server-info.php">mysqli::$server_info</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-info.php">mysql_info</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.info.php">mysqli::$info</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-insert-id.php">mysql_insert_id</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.insert-id.php">mysqli::$insert_id</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.lastinsertid.php">PDO::lastInsertId</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-dbs.php">mysql_list_dbs</a></td>
    <td>Query: SHOW DATABASES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-fields.php">mysql_list_fields</a></td>
    <td>Query: SHOW COLUMNS</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-processes.php">mysql_list_processes</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.thread-id.php">mysqli::$thread_id</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-list-tables.php">mysql_list_tables</a></td>
    <td>Query: SHOW TABLES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-num-fields.php">mysql_num_fields</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.field-count.php">mysqli::$field_count</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.columncount.php">PDOStatement::columnCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-num-rows.php">mysql_num_rows</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli-stmt.num-rows.php">mysqli_stmt::$num_rows</a></td>
    <td><a href="http://www.php.net/manual/en/pdostatement.rowcount.php">PDOStatement::rowCount</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-pconnect.php">mysql_pconnect</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.construct.php">mysqli::__construct</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-ping.php">mysql_ping</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.ping.php">mysqli::ping</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-query.php">mysql_query</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.query.php">mysqli::query</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.query.php">PDO::query</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-real-escape-string.php">mysql_real_escape_string</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.real-escape-string.php">mysqli::real_escape_string</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.quote.php">PDO::quote</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-result.php">mysql_result</a></td>
    <td>Combination</td>
    <td><a href="http://www.php.net/manual/en/pdostatement.fetchcolumn.php">PDOStatement::fetchColumn</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-select-db.php">mysql_select_db</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.send-query.php">mysqli::send_query</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-set-charset.php">mysql_set_charset</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.character-set-name.php">mysqli::character_set_name</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.construct.php">PDO::__construct</a></td></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-stat.php">mysql_stat</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.stat.php">mysqli::stat</a></td>
    <td><a href="http://www.php.net/manual/en/pdo.getattribute.php">PDO::getAttribute</a></td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-tablename.php">mysql_tablename</a></td>
    <td>Query: SHOW TABLES</td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-thread-id.php">mysql_thread_id</a></td>
    <td><a href="http://www.php.net/manual/en/mysqli.thread-id.php">mysqli::$thread_id</a></td>
    <td> </td>
    </tr>
<tr><td><a href="http://www.php.net/manual/en/function.mysql-unbuffered-query.php">mysql_unbuffered_query</a></td>
    <td>See <a href="http://www.php.net/manual/en/mysqlinfo.concepts.buffering.php">Buffering Concepts</a></td>
    <td> </td>
    </tr>
</table>

</div><!-- container -->
0
Ray Paseur