Neden PHP'de mysql_ * işlevlerini kullanmamalıyım?


2502

Birinin mysql_*işlevleri kullanmaması için teknik nedenler nelerdir ? (örneğin mysql_query(), mysql_connect()ya da mysql_real_escape_string())?

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

Sitemde çalışmıyorlarsa neden aşağıdaki gibi hatalar alıyorum?

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


Hata gibi: Önemli hata: Yakalanmadı Hata: Tanımlanmamış işleve çağrı mysql_connect () ...
Bimal Poudel

21
Onları önlemek için tek başına kullanımdan
kaldırıldı

Yanıtlar:


2088

MySQL uzantısı:

  • Aktif gelişme altında değil
  • Is resmen kaldırılmış PHP 5.5 itibariyle (Haziran 2013 yayınlandı).
  • Edildi kaldırıldı tamamen PHP 7.0 itibariyle (2015 Aralık yayınlandı)
    • Bu 31 Aralık 2018 itibarıyla PHP'nin desteklenen herhangi bir sürümünde bulunmadığı anlamına gelir . PHP'yi destekleyen bir sürüm kullanıyorsanız, güvenlik sorunlarını çözmeyen bir sürüm kullanıyorsunuz.
  • OO arayüzü yok
  • Desteklemiyor:
    • Engellemeyen, eşzamansız sorgular
    • Hazırlanan ifadeler veya parametreli sorgular
    • Saklı yordamlar
    • Çoklu İfadeler
    • işlemler
    • "Yeni" şifre kimlik doğrulama yöntemi (varsayılan olarak MySQL 5.6'da açık; 5.7'de gereklidir)
    • MySQL 5.1 veya sonraki sürümlerdeki yeni işlevlerden herhangi biri

Kullanımdan kaldırıldığı için, kodunuzu kullanmak daha az gelecekteki kanıtı oluşturur.

Hazırlanan ifadeler için destek eksikliği, harici verilerden ayrı bir işlev çağrısıyla manuel olarak kaçmaktan daha açık, daha az hataya eğilimli bir yöntem sağladığından özellikle önemlidir.

SQL uzantılarının karşılaştırmasına bakın .


287
Onlardan kaçınmak için tek başına reddedildi. Bir gün orada olmayacaklar ve onlara güvenirseniz mutlu olmayacaksınız. Gerisi sadece eski uzantıları kullanmanın insanları öğrenmesini engellediği şeylerin bir listesidir.
Tim Post

111
Yoksunluk, herkesin sandığı sihirli kurşun değildir. PHP'nin kendisi bir gün orada olmayacak, ancak bugün elimizde olan araçlara güveniyoruz. Araçları değiştirmek zorunda kaldığımızda, değiştireceğiz.
Yörüngedeki Hafiflik Yarışları

133
@LightnessRacesinOrbit - Kullanımdan çıkarma sihirli bir kurşun değil, "Bu berbat olduğunun farkındayız, bu yüzden daha uzun süre desteklemeyeceğiz" diyen bir bayrak. İleride kodun daha iyi bir şekilde kanıtlanmasına sahip olmak, kullanımdan kaldırılan özelliklerden uzaklaşmak için iyi bir neden olsa da, tek olan (hatta ana kod) değil. Araçları değiştirin çünkü zorlandığınız için değil, daha iyi araçlar vardır. (Ve zorlamadan önce araçları değiştirmek, kodunuzun çalışmayı durdurması ve düzeltilmesi gerektiğinden yeni olanları öğrenmemeniz anlamına gelir… yeni araçları öğrenmek için en kötü zaman budur).
Quentin

18
Hazırlanan ifadelerin eksikliğinden bahsetmediğim bir şey performans konusudur. Her ifade verdiğinizde, MySQL arka plan programının bunu anlayabilmesi için bir şeyler derlemek zorundadır. Bu API ile, aynı sorgunun 200.000'ini bir döngüde yayınlarsanız, sorgunun MySQL için bunu anlaması için 200.000 kez derlenmesi gerekir. Hazırlanan ifadelerle, bir kez derlenir ve sonra değerler derlenmiş SQL'e parametrelendirilir.
Goldentoa11

20
@symcbean, Kesinlikle yok değil hazır deyimleri destekler. Aslında, kullanımdan kaldırılmasının ana nedeni budur. (Kullanımı kolay) hazırlanan ifadeler olmadan mysql uzantısı genellikle SQL enjeksiyon saldırılarına kurban gitmektedir.
rustyx

1287

PHP, MySQL'e bağlanmak için üç farklı API sunar. Bunlar mysql(PHP 7'den itibaren kaldırılmıştır) mysqlive PDOuzantılardır.

mysql_*Fonksiyonları çok popüler olarak kullanılan, ancak bunların kullanımı artık teşvik edilmez. Dokümantasyon ekibi, veritabanı güvenlik durumunu tartışıyor ve kullanıcıları yaygın olarak kullanılan ext / mysql uzantısından uzaklaşmaları için eğitiyor .

Ve daha sonra PHP geliştiricisi takım oluşturmak için karar aldı E_DEPRECATED, içinden Kullanıcıların, MySQL bağlandıklarında hataları mysql_connect(), mysql_pconnect()ya yerleşik örtülü bağlantı işlevselliği ext/mysql.

ext/mysqloldu resmen PHP 5.5 tarihinden itibaren kullanımdan kaldırılmıştır ve olmuştur PHP 7'nin olarak uzaklaştırıldı .

Kırmızı Kutuyu görüyor musun?

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

Neden


Uzaklaşmak ext/mysqlsadece güvenlikle ilgili değil, aynı zamanda MySQL veritabanının tüm özelliklerine erişim ile ilgilidir.

ext/mysqlMySQL 3.23 için üretildi ve o zamandan beri sadece çok az sayıda ekleme aldı ve kodun bakımını biraz zorlaştıran bu eski sürümle uyumluluğu korudu. Tarafından desteklenmeyen eksik özellikler ext/mysqlşunlardır: ( PHP kılavuzundan ).

mysql_*Fonksiyonu kullanmama nedeni :

  • Aktif gelişme altında değil
  • PHP 7'den kaldırıldı
  • OO arayüzü yok
  • Engellemeyen, eşzamansız sorguları desteklemez
  • Hazırlanan ifadeleri veya parametreli sorguları desteklemez
  • Saklı yordamları desteklemiyor
  • Birden fazla ifadeyi desteklemiyor
  • İşlemleri desteklemiyor
  • MySQL 5.1'deki tüm işlevleri desteklemez

Quentin'in cevabından alıntılanan yukarıdaki nokta

Hazırlanan ifadeler için destek eksikliği, ayrı bir işlev çağrısıyla manüel olarak kaçmaktan daha çok, daha açık, daha az hataya eğilimli bir dış veri kaçırma ve alıntılama yöntemi sağladığından önemlidir.

SQL uzantılarının karşılaştırmasına bakın .


Kullanımdan kaldırma uyarılarını bastırmak

Kod dönüştürülen edilirken MySQLi/ PDO, E_DEPRECATEDayarlayarak hatalar bastırılabilir error_reportingiçinde php.ini dışlamak içinE_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

Bunun ayrıca , MySQL dışındaki şeyler için olabilecek diğer kullanımdan çıkarma uyarılarını da gizleyeceğini unutmayın . ( PHP kılavuzundan )

PDO ve MySQLi makalesi : Hangisini Kullanmalısınız? tarafından Dejan Marjanovic seçtiğiniz için yardımcı olacaktır.

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


Basit ve kısa PDO eğitimi


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

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

alternatif metin


MySQL'e bağlanma

İle mysql_*biz eski şekilde söyleyebiliriz fonksiyonu ya da (yukarıda PHP'de 5.5 ve kullanımdan kaldırıldı)

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

İle PDO: Tek yapmanız gereken yeni bir PDOnesne yaratmak . Yapıcı veritabanı kaynağı belirlemek için parametreleri kabul PDOsitesindeki yapıcı çoğunlukla dört parametre yer alır DSN, isteğe bağlı olarak (veri kaynağı adı) ve username, password.

Burada bence her şeyi biliyorsunuz DSN; bu yeni PDO. A DSNtemel olarak PDOhangi sürücünün kullanılacağını ve bağlantı ayrıntılarını belirten bir seçenek dizesidir . Daha fazla referans için PDO MySQL DSN'yi kontrol edin .

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

Not: Ayrıca kullanabilirsiniz charset=UTF-8, ancak bazen bir hataya neden olur, bu nedenle kullanmak daha iyidir utf8.

Herhangi bir bağlantı hatası varsa, daha fazla PDOExceptionişlemek için yakalanabilecek bir nesne atar Exception.

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

Ayrıca dördüncü parametreye dizi olarak çeşitli sürücü seçeneklerini de aktarabilirsiniz. PDOİstisna moduna geçiren parametreyi geçirmenizi öneririm . Bazı PDOsürücüler yerel hazırlanmış ifadeleri desteklemediğinden PDO, hazırlamanın öykünmesini gerçekleştirir. Ayrıca bu öykünmeyi el ile etkinleştirmenizi sağlar. Sunucu tarafında hazırlanan yerel ifadeleri kullanmak için, ifadeyi açıkça ayarlamanız gerekir false.

Diğeri, MySQLvarsayılan olarak sürücüde etkinleştirilmiş olan öykünme hazırlamayı kapatmaktır , ancak PDOgüvenli bir şekilde kullanmak için öykünme hazırlığı kapatılmalıdır .

Daha sonra öykünme hazırlamanın neden kapatılması gerektiğini açıklayacağım. Sebep bulmak için lütfen bu gönderiyi kontrol edin .

Yalnızca önermediğim eski bir sürümünü kullanıyorsanız kullanılabilir MySQL.

Aşağıda bunu 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 yapımından sonra nitelikleri ayarlayabilir miyiz?

Evet , PDO yapıldıktan sonra setAttributeyöntemle bazı öznitelikler 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 yönetimi


Hata işleme de çok daha kolaydır PDOdaha mysql_*.

Kullanırken yaygın bir uygulama mysql_*:

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

OR die()bir şeyi işleyemediğimiz için hatayı işlemek için iyi bir yol değildir die. Sadece komut dosyasını aniden sonlandıracak ve sonra hatayı genellikle son kullanıcılarınıza göstermek istemediğiniz ekrana yansıtacak ve kanlı bilgisayar korsanlarının şemanızı keşfetmesine izin verecektir. Alternatif olarak, mysql_*işlevlerin dönüş değerleri genellikle hataları işlemek için mysql_error () ile birlikte kullanılabilir .

PDOdaha iyi bir çözüm sunar: istisnalar. Yaptığımız her şey PDObir try- catchbloğa sarılmalıdır . PDOHata modu özelliğini ayarlayarak üç hata modundan birine girebiliriz . Üç hata işleme modu aşağıdadır.

  • PDO::ERRMODE_SILENT. Sadece hata kodlarını ayarlamak ve mysql_*her bir sonucu kontrol etmeniz gereken yere benzer şekilde davranır ve daha sonra $db->errorInfo();hata ayrıntılarını almak için bakın.
  • PDO::ERRMODE_WARNINGYükselt E_WARNING. (Çalışma zamanı uyarıları (önemli olmayan hatalar). Komut dosyasının yürütülmesi durdurulmaz.)
  • PDO::ERRMODE_EXCEPTION: İstisnalar atın. PDO tarafından oluşturulan bir hatayı temsil eder. PDOExceptionKendi kodunuzdan a atmamalısınız . PHP'deki istisnalar hakkında daha fazla bilgi için Kural Dışı Durumlar konusuna bakın . or die(mysql_error());Yakalanmadığı zaman çok benzer . Ama aksine or die(), PDOExceptionbunu seçerseniz yakalanabilir ve ele alınabilir.

İ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- içine sarabilirsiniz catch:

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());
}

Bununla başa çıkmak zorunda değilsiniz try- catchşu anda. İstediğiniz zaman yakalayabilirsiniz, ancak kullanmanızı kesinlikle öneririz try- catch. Ayrıca, PDOöğeleri çağıran fonksiyonun 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, idare edebilirsin or die()ya da böyle diyebiliriz mysql_*, ama gerçekten değişecektir. Üretimdeki tehlikeli hata mesajlarını display_errors off, hata günlüğünüzü çevirip okuyarak gizleyebilirsiniz .

Şimdi, yukarıdaki her şeyi okuduktan sonra, muhtemelen düşünüyorsun: halt ne olduğunu ben sadece basit eğilerek başlamak istediğinizde SELECT, INSERT, UPDATEveya DELETEifadeleri? Endişelenme, işte başlıyoruz:


Veri Seçme

PDO görüntü seç

Yani yaptığınız mysql_*şey:

<?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, 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öntem ( query()) gibi bir yöntem kullanıyorsanız , bu yöntem bir PDOStatementnesne döndürür . Sonuç almak istiyorsanız, yukarıdaki gibi kullanın.

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

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

Getirme Modları

Yukarıdaki ve kodundaki kullanımına dikkat PDO::FETCH_ASSOCedin . Bu , satırların alan adları ile ilişkilendirilebilir bir dizi olarak anahtarlar olarak döndürülmesini söyler . Tek tek açıklayacağım başka birçok getirme modu da var.fetch()fetchAll()PDO

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

 $stmt->fetch(PDO::FETCH_ASSOC)

Yukarıda, kullanıyorum fetch(). Ayrıca kullanabilirsiniz:

Şimdi getirme moduna geliyorum:

  • PDO::FETCH_ASSOC: sonuç kümenizde döndürülen sütun adına göre dizine eklenen bir dizi döndürür
  • PDO::FETCH_BOTH (varsayılan): sonuç kümenizde döndürülen şekilde hem sütun adı hem de 0 dizinli sütun numarasıyla dizinlenmiş bir dizi döndürür

Daha fazla seçenek var! Bunların hepsini PDOStatementGetirme belgelerinde okuyun . .

Satır sayısını elde etme :

mysql_num_rowsDöndürülen satır sayısını almak için kullanmak yerine, a PDOStatementve do komutlarını alabilirsiniz rowCount(), örneğin:

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

Son Eklenen Kimliği Alma

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

Ekleme ve Güncelleme veya Silme

PDO resmi ekleme ve güncelleme

mysql_*İşlev olarak ne yapıyoruz :

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

Ve pdo'da aynı şey şu şekilde yapılabilir:

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

Yukarıdaki sorguda PDO::execbir SQL deyimi 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 kullanışlıdır. Ancak bir sorguda bir değişken kullanmanız gerektiğinde, asla yukarıdaki gibi denemeyin ve orada hazırlanmış deyimi veya parametreli deyimi vardır.


Hazırlanan İfadeler

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

Hazırlanan bir ifadeyi kullanmanın tipik iş akışı aşağıdaki gibidir ( Wikipedia üç 3 maddeden alıntılanmıştır ):

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

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

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

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

SQL'inize yer tutucular ekleyerek hazırlanmış bir ifade kullanabilirsiniz. Temel olarak yer tutucuları olmayan üç tane vardır (bunu birincisi değişkeniyle denemeyin), biri isimsiz yer tutucuları ve diğeri adlandırılmış yer tutucuları ile.

S. Şimdi, yer tutucular olarak adlandırılan nedir ve nasıl kullanılır?
A. Adlandırılmış yer tutucular. Soru işaretleri yerine iki nokta üst üste işareti bulunan açıklayıcı adları kullanın. İsim yer sahibindeki konum / değer sırası umursamıyoruz:

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

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

Ayrıca bir yürütme dizisi 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);

OOPArkadaşlar için bir diğer güzel özellik , adlandırılmış yer tutucuların, özelliklerin adlandırılan alanlarla eşleştiği varsayılarak doğrudan veritabanınıza nesne 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);

S. Şimdi, adlandırılmamış 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 tutucusundaki gibi bir ad yerine bunları görebilirsiniz . Şimdi ilk örnekte, çeşitli yer tutuculara ( $stmt->bindValue(1, $name, PDO::PARAM_STR);) değişkenler atarız . Ardından, bu yer tutuculara değerler atar ve ifadeyi yürütürüz. İkinci örnekte, ilk dizi elemanı, birinci gider ?ve ikinci ikinci ?.

NOT : Adsız yer tutucularda , diziye PDOStatement::execute()yönteme geçirdiğimiz öğelerin uygun sırasına dikkat etmeliyiz .


SELECT, INSERT, UPDATE, DELETESorgular hazırlanan

  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 PDOve / veya MySQLitamamen güvenli değildir. Cevabı kontrol edin PDO hazırlanmış ifadeler SQL enjeksiyonunu önlemek için yeterli mi? ircmaxell tarafından . Ayrıca, cevabından bir kısmını alıntılı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 /*"));

15
Yukarıda iyi okunan şeyden bahsetmek gerekir ki: hazırlanmış ifade IN (...) construct.
Eugen Rieck

24
Soru "Neden PHP'de mysql_ * işlevlerini kullanmamalıydım" idi. Bu cevap, etkileyici ve yararlı bilgilerle dolu olsa da, WAY kapsam dışına çıkıyor ve @trejder'in dediği gibi - 10 kişiden 8'i bu bilgileri kaçırmayacak, çünkü üzerinde çalışmaya çalışmak için 4 saatleri yok o. Bu çok daha kıymetli olurdu ve birkaç, daha kesin soruya cevap olarak kullanılır.
Alex McMillan

Ben mysqli ve PDO'yu tercih ederim. Ama kalıp işleme için, istisna alternatif denedim İstisna function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx();atmak için çalışır.
kuldeep.kamboj

Doesn't support non-blocking, asynchronous queriesmysql_ kullanmamanın bir nedeni olarak listeliyorsunuz - PDO'yu kullanmamanın bir nedeni olarak da listelemelisiniz, çünkü PDO da desteklemez. (ancak MySQLi destekliyor)
hanshenrik

Bunu kullanan bir veritabanı var gibi Charset utf8mb4_unicode_ci kullanmak mümkün mü?
Ryan Stone

301

İlk olarak, herkese verdiğimiz standart yorumla başlayalım:

Lütfen mysql_*yeni kodda işlevleri kullanmayın . Artık bakımları yapılmıyor ve resmi olarak kullanımdan kaldırılıyor . Bkz kırmızı kutuyu ? Hazırlanan ifadeler hakkında bilgi edininBunun yerine ve PDO veya MySQLi kullanın - bu makale hangisine karar vermenize yardımcı olacaktır. PDO'yu seçerseniz, burada iyi bir öğretici var .

Bunu ele alalım, cümle ile cümle ve açıklayalım:

  • Artık bakımları yapılmıyor ve resmi olarak kullanımdan kaldırılıyor

    Bu, PHP topluluğunun bu çok eski işlevler için desteği yavaş yavaş bıraktığı anlamına gelir. PHP'nin gelecekteki (son) sürümünde bulunmayacaklar! Bu işlevlerin sürekli kullanımı, kodunuzu (çok da değil) çok ileride bozabilir.

    YENİ! - ext / mysql artık PHP 5.5'ten itibaren resmi olarak kullanımdan kaldırıldı!

    Daha yeni! ext / MySQL PHP 7'de kaldırıldı .

  • Bunun yerine, hazırlanan ifadeleri öğrenmelisiniz

    mysql_*uzantısı hazırlanmış ifadeleri desteklemez , bu (diğer şeylerin yanı sıra) SQL Injection'a karşı çok etkili bir önlem . MySQL bağımlı uygulamalarda, saldırganların senaryonuza erişmesini ve veritabanınızda olası herhangi bir sorguyu 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ı Kutuyu görüyor musun?

    Herhangi birine gittiğinizde mysql işlev kılavuzu sayfası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 iyi inşa edilmiş alternatifler, veritabanı etkileşimine tam bir OOP yaklaşımı sunan PDO - PHP Veritabanı Nesnesi ve MySQL'e özel bir iyileştirme olan MySQLi vardır.


6
Bir şey daha var: işlevin sadece bir nedenden ötürü PHP'de hala var olduğunu düşünüyorum - eski, modası geçmiş ancak hala çalışan CMS, e-ticaret, bülten tahtası sistemleri vb. İle uyumludur. uygulama ...
Kamil

4
@Kamil: Bu doğru, ama onu kullanmamanın bir nedeni değil. Kullanmamanın nedeni eski, güvensiz vb. Olmasıdır.
Madara'nın Hayaleti

4
@Mario - PHP geliştiricilerinin bir süreci var ve 5.5'ten beri ext / mysql'yi resmen reddetme lehine oy kullandılar. Artık varsayımsal bir mesele değil.
SDC

2
PDO veya MySQLi gibi kanıtlanmış bir teknikle birkaç satır daha eklemek PHP'nin her zaman sunduğu kullanım kolaylığını sağlar. Umarım geliştirici uğruna bu tanrısal korkunç mysql_ * işlevlerini herhangi bir öğreticide görmenin aslında dersten düştüğünü bilir ve OP'ye bu tür kodların 10 yıl önce soooo olduğunu söylemelidir. öğreticinin alaka düzeyi de!
FredTheWebGuy

1
Cevabın açıkça belirtmesi gerekenler: hazırlanan açıklama IN (...) construct,.
Eugen Rieck

217

Kullanım kolaylığı

Analitik ve sentetik nedenlerden daha önce bahsedilmişti. Yeni gelenler için tarihli mysql_ işlevlerini kullanmayı durdurmak için daha önemli bir teşvik vardır.

Çağdaş veritabanı API'lerinin kullanımı daha kolaydır .

Çoğunlukla kodu basitleştirebilen bağlı parametrelerdir . Ve mükemmel öğreticilerle (yukarıda görüldüğü gibi) PDO'ya geçiş aşırı zahmetli değildir.

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

Eşdeğer pdo_ * yerine işlevleri mysql_ *

< Pdo_mysql.php > kullanarak , eski mysql_ işlevlerinden en az çabayla geçiş yapabilirsiniz . pdo_Muadillerinin yerine işlev sarmalayıcılar ekler mysql_.

  1. Basitçe veritabanı ile etkileşim vardır her çağırma senaryodaki. include_once("pdo_mysql.php");

  2. mysql_İşlev önekini her yerde kaldırın ve ile değiştirin pdo_.

    • 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 bunun gibi...

  3. Kodunuz benzer şekilde çalışır ve yine de çoğunlukla aynı görünür:

    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 PDO kullanıyor .
Şimdi onu kullanma zamanı .

Bağlı parametrelerin kullanımı kolay olabilir

Sadece daha az kullanışsız bir API'ya ihtiyacınız var.

pdo_query()bağlı parametreler için çok kolay destek sağlar. Eski kodu dönüştürmek kolaydır:

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

  • Bunları virgülle ayrılmış işlev parametreleri olarak ekleyin pdo_query().
  • Soru işaretlerini ?değişkenlerin bulunduğu yer tutucuları olarak yerleştirin.
  • 'Önceden eklenmiş dize değerlerini / değişkenlerini içeren tek tırnaklardan kurtulun .

Daha uzun kod için avantaj daha belirgin hale gelir.

Genellikle dize değişkenleri sadece SQL'e enterpole edilmez, aynı zamanda aralarında 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 uygulandığında, bununla uğraşmanıza gerek kalmaz:

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

Pdo_ * 'nın hala ya da izin verdiğini unutmayın .
Sadece bir değişken kaçış yok ve aynı sorguda bağlamak.

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

Daha da önemlisi, $ _REQUEST [] değişkenlerini herhangi bir sorgunun arkasına güvenle geçirebilirsiniz. Gönderilen <form>alanlar veritabanı yapısıyla tam olarak eşleştiğinde daha da kısadır:

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

Çok basitlik. Ancak, neden yeniden kurtulmak mysql_ve kaçmak isteyebileceğinizle ilgili bazı yeniden yazma önerilerine ve teknik nedenlere geri dönelim .

Eski okul sanitize()işlevlerini düzeltin veya kaldırın

Tüm mysql_çağrıları pdo_queryilişkili parametrelerle dönüştürdüğünüzde , tüm gereksiz pdo_real_escape_stringçağrıları kaldırın .

Özellikle tarihli öğreticiler tarafından bildirilen herhangi bir sanitizeveya clean/ filterThisveya clean_dataişlevi bir biçimde veya diğerinde düzeltmelisiniz :

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

Buradaki en göze çarpan hata, dokümantasyon eksikliğidir. Daha da önemlisi, filtreleme sırası tam olarak yanlış sıradaydı.

  • Doğru düzen olurdu: deprecatedly stripslashesiçteki araması olarak, daha sonra trim, sonradan strip_tags, htmlentitiessadece son çıkış bağlamı ve için _escape_stringonun uygulama olarak doğrudan intersparsing SQL preceed olmalıdır.

  • Ama ilk adım olarak sadece çağrıdan kurtulun_real_escape_string .

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

  • Dize / değer işleme PDO'ya ve parametreli ifadelerine devredilir.

  • stripslashes()Sanitize etme fonksiyonunuzda herhangi bir şey varsa , bu daha yüksek bir gözetim olduğunu gösterebilir.

    Magic_quotes tarihi notu. Bu özellik haklı olarak kullanımdan kaldırıldı. Ancak genellikle hatalı güvenlik özelliği olarak yanlış tasvir edilir . Ancak magic_quotes, tenis topları beslenme kaynağı olarak başarısız olduğu kadar başarısız bir güvenlik özelliğidir. Amaçları bu değildi.

    PHP2 / FI'daki orijinal uygulama, sadece " tırnak işaretleri otomatik olarak kaçarak form verilerinin doğrudan msql sorgularına aktarılmasını kolaylaştırır " ile tanıtıldı . Özellikle , sadece ASCII'yi desteklediği için mSQL ile kullanılması güvenli bir şekilde güvenlidir .
    Daha sonra PHP3 / Zend, MySQL için magic_quotes'u yeniden tanıttı ve yanlış belgeledi. Ama aslında güvenlik için değil , sadece kolaylık sağlayan bir özellikti .

Hazırlanan ifadeler arasındaki farklar

Dize değişkenlerini SQL sorgularına karıştırdığınızda, izlemeniz daha karmaşık hale gelmez. Ayrıca MySQL'in kodu ve verileri tekrar ayırması gayret gösterir.

SQL enjeksiyonları sadece verilerin koda karıştığı zamandır içeriğine . Bir veritabanı sunucusu daha sonra PHP'nin sorgu cümleleri arasındaki başlangıçta yapıştırılmış değişkenleri tespit edemez.

Bağlı parametrelerle SQL kodunuzu ve SQL bağlam değerlerini PHP kodunuzda ayırırsınız. Ancak sahne arkasında tekrar karıştırılmaz (PDO :: EMULATE_PREPARES hariç). Veritabanınız, değiştirilmemiş SQL komutlarını ve 1: 1 değişken değerlerini alır.

Bu cevap, düşmenin okunabilirlik avantajlarını önemsemeniz gerektiğini vurguluyor mysql_. Bu görünür ve teknik veri / kod ayrımı nedeniyle bazen bir performans avantajı (sadece farklı değerlere sahip tekrarlanan INSERT'ler) vardır.

Hala bağlayıcı bu parametreyi dikkat karşı sihirli bir tek durak çözüm değil bütün SQL enjeksiyonlarına . Veri / değerler için en yaygın kullanımı yönetir. Ancak sütun adı / tablo tanımlayıcılarını beyaz listeye ekleyemez, dinamik yan tümce oluşturma konusunda yardımcı olamaz veya yalnızca düz dizi değeri listelerini oluşturamaz.

Hibrit PDO kullanımı

Bu pdo_*sarmalayıcı işlevleri kodlama dostu bir dur-boşluk API'sı yapar. ( MYSQLIEğer kendine özgü fonksiyon imza kayması olmasaydı ne olabilirdi). Ayrıca çoğu zaman gerçek PDO'yu ortaya çıkarırlar.
Yeniden yazma işleminin yeni pdo_ işlev adlarını kullanmayı bırakması gerekmez. Her pdo_query () öğesini düz bir $ pdo-> prepar () -> execute () çağrısına tek tek geçebilirsiniz.

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

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

Sadece bir foreach yinelemesi ile değiştirilebilir:

foreach ($result as $row) {

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

$result->fetchAll();

Çoğu durumda PDO veya mysql_ genellikle başarısız sorgulardan sonra sağlanandan daha yararlı uyarılar alırsınız.

Diğer seçenekler

Yani bu, umarım bazı pratik nedenleri ve düşmeye değer bir yolu görselleştirmiştir mysql_.

Sadece tam olarak kesmiyor. pdo_query()aynı zamanda sadece bir ön uçtur.

Ayrıca parametre bağlamayı tanıtmazsanız veya daha hoş bir API'den başka bir şey kullanamazsanız, bu anlamsız bir anahtardır. Umarım yeni gelenlerin cesaretini daha da ileriye götüremeyecek kadar basit tasvir edilir. (Eğitim genellikle yasaklardan daha iyi çalışır.)

Muhtemelen işe yarayabilecek en basit-şey-şey-kategorisi için uygun olsa da, yine de çok deneysel kod. Sadece hafta sonu yazdım. Ancak çok sayıda alternatif var. Sadece PHP veritabanı soyutlama için google ve biraz göz atın. Bu tür görevler için her zaman mükemmel kütüphaneler olmuştur ve olacaktır.

Veritabanı etkileşiminizi daha da basitleştirmek istiyorsanız, Paris / Idiorm gibi haritacılar denemeye değer. Hiç kimse artık JavaScript'te mülayim DOM'u kullanmıyorsa, günümüzde ham bir veritabanı arayüzüne bakmanıza gerek yok.


8
Bu pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);işleve dikkat edin - yani:pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');
rickyduck

@Tom Tabii, çok fazla korunmasa da (0.9.2 sonuncuydu), bir fosil hesabı oluşturabilir , wiki'ye ekleyebilir veya bir hata raporu (IIRC kaydı olmadan) dosyalayabilirsiniz.
mario

pdo_real_escape_string() Bu gerçek bir işlev mi, bunun için herhangi bir belge bulamıyorum? Lütfen bunun için bir kaynak gönderin.
Ryan Stone

144

mysql_fonksiyonlar:

  1. eski - artık bakımları yapılmıyor
  2. başka bir veritabanı arka ucuna kolayca geçmenize izin verme
  3. bu yüzden hazırlanmış ifadeleri desteklemeyin
  4. programcıları sorgu oluşturmak için birleştirme kullanmaya teşvik ederek SQL enjeksiyon güvenlik açıklarına yol açar

18
# 2 eşit derecede doğrudurmysqli_
eggyal

16
adil olmak gerekirse, SQL lehçesindeki varyasyonlar göz önüne alındığında, PDO bile herhangi bir kesinlikte # 2 vermez. Bunun için uygun bir ORM ambalajına ihtiyacınız var.
SDC

mysql_*fonksiyon yeni PHP sürümleri için mysqlnd fonksiyonları içine bir kabuk vardır. Eski istemci kitaplığı artık korunmasa bile,
mysqlnd

Sorun, pek çok web barındırma sağlayıcısı, eski php sürümü nedeniyle böyle bir nesne odaklı tasarım stilini destekleyemez
Raju yourPepe

@RajuGujarati böylece bir web barındırma bulabilirsiniz. Web barındırıcınız yapmazsa, sunucularındaki saldırılara karşı savunmasız olmaları çok yüksektir.
Alnitak

106

Teknik nedenlerden bahsetmişken, sadece birkaç, son derece spesifik ve nadiren kullanılır. Büyük olasılıkla onları asla hayatınızda kullanmayacaksınız.
Belki çok cahilim, ama onlara asla böyle şeyleri kullanma fırsatı bulamadım

  • engellemeyen, eşzamansız sorgular
  • birden çok sonuç kümesi döndüren saklı yordamlar
  • Şifreleme (SSL)
  • Sıkıştırma

Onlara ihtiyacınız varsa - bunlar şüphesiz mysql uzantısından daha şık ve modern görünümlü bir şeye doğru hareket etmenin teknik nedenleridir.

Yine de, deneyiminizi biraz daha zorlaştırabilecek teknik olmayan bazı sorunlar da vardır.

  • Bu işlevlerin modern PHP sürümleriyle daha fazla kullanılması kullanımdan kaldırılmış düzey bildirimleri yükseltir. Basitçe kapatılabilirler.
  • uzak bir gelecekte, muhtemelen varsayılan PHP derlemesinden kaldırılabilir. Mydsql ext PECL içine taşınacak ve her barındırıcı PHP onlarla derlemek için mutlu olacak, çünkü onlarca yıldır siteleri çalışan müşterilerini kaybetmek istemiyorlar.
  • Stackoverflow topluluğundan güçlü direnç. Her zaman bu dürüst işlevlerden bahsettiğinizde, onlara sıkı tabu altında oldukları söyleniyor.
  • ortalama bir PHP kullanıcısı olarak, muhtemelen bu işlevleri kullanma fikriniz hataya açık ve yanlıştır. Sadece size yanlış yolu öğreten bu çok sayıda öğretici ve kılavuz nedeniyle. Fonksiyonların kendileri değil - vurgulamak zorundayım - ama kullanım şekilleri.

Bu ikinci sorun bir sorundur.
Ancak, bence, önerilen çözüm daha iyi değil.
Bana göre çok idealist bir rüya gibi tüm bu PHP kullanıcıları SQL sorguları bir kerede düzgün işlemeyi öğrenecek. Büyük olasılıkla, mysql_ * 'ı mekanik olarak mysqli_ * olarak değiştirecekler ve yaklaşımı aynı bırakacaklardı . Özellikle mysqli hazırlanmış ifadeler kullanımını inanılmaz acı verici ve zahmetli hale getirdiğinden. Hazırlanan yerel ifadelerin korumak için yeterli olmadığından
bahsetmiyorum SQL enjeksiyonlarından ve ne mysqli ne de PDO bir çözüm sunmuyor.

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

Ayrıca, bazı yanlış veya önemli olmayan nedenler vardır, örneğin

  • Saklı Yordamları desteklemiyor (uzun zamandır kullanıyorduk mysql_query("CALL my_proc");)
  • İşlemleri desteklemez (yukarıdakiyle aynı)
  • Birden Çok İfadeyi desteklemiyor (kimin ihtiyacı var?)
  • Aktif gelişme altında değil (peki sizi pratikte herhangi bir şekilde etkiler mi ?)
  • OO arayüzü yok (bir tane oluşturmak birkaç saat meselesi)
  • Hazırlanan İfadeleri veya Parametreli Sorguları desteklemez

Sonuncusu ilginç bir nokta. Mysql ext yerel olarak hazırlanmış ifadeleri desteklemese de güvenlik için gerekli değildir. El ile işlenen yer tutucular kullanarak hazırlanmış ifadeleri kolayca taklit edebiliriz (tıpkı 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ğenmezseniz, bir seçim sorunu ortaya çıkar: mysqli veya PDO?

Cevap şu şekilde olacaktır:

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

    • mysqli'den farklı olarak PDO, yer tutucuları değere bağlayabilir , bu da dinamik olarak oluşturulmuş sorguları oldukça dağınık kodun birkaç ekranı olmadan mümkün kılar.
    • mysqli aksine, PDO her zaman basit bir olağan dizi sorgu sonucu döndürebilir, mysqli bunu sadece mysqlnd kurulumlarında yapabilirsiniz.

Yani, ortalama bir PHP kullanıcısıysanız ve yerel hazırlanmış ifadeler kullanırken kendinizi bir ton baş ağrısından kurtarmak istiyorsanız, PDO - tekrar - tek seçimdir.
Bununla birlikte, PDO da gümüş bir kurşun değildir ve zorlukları vardır.
Bu yüzden, PDO etiketi wiki'sindeki tüm yaygın tuzaklar ve karmaşık durumlar için çözümler yazdım

Bununla birlikte, uzantılardan bahseden herkes Mysqli ve PDO hakkında 2 önemli gerçeği her zaman eksik :

  1. Hazırlanan ifade gümüş bir kurşun değildir . Hazırlanan ifadeler kullanılarak bağlanamayan dinamik tanımlayıcılar vardır. Sorgu oluşturmayı zor bir görev haline getiren bilinmeyen sayıda parametreye sahip dinamik sorgular vardır.

  2. Uygulama kodunda ne mysqli_ * ne de PDO işlevleri görünmemelidir.
    Aralarında uygulama kodunun KURU ve temiz olmasını sağlayan, ciltleme, döngü, hata işleme vb. Gibi tüm kirli işleri yapacak bir soyutlama katmanı ve uygulama kodu olmalıdır. Özellikle dinamik sorgu oluşturma gibi karmaşık durumlar için.

Yani, sadece PDO veya mysqli'ye geçmek yeterli değildir. Kodlarında ham API işlevlerini çağırmak yerine ORM veya sorgu oluşturucu veya herhangi bir veritabanı soyutlama sınıfı kullanılmalıdır.
Aksine - uygulama kodunuz ile mysql API arasında bir soyutlama katmanınız varsa - aslında hangi motorun kullanıldığı önemli değildir. Kullanımdan kaldırılana kadar mysql ext komutunu kullanabilir ve ardından tüm uygulama kodunu değiştirmeden soyutlama sınıfınızı başka bir motora kolayca yeniden yazabilirsiniz .

İşte böyle bir soyutlama sınıfının nasıl olması gerektiğini göstermek için safemysql sınıfımı temel alan 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 olacak kod miktarı ile karşılaştırın .
Sonra ham Mysqli hazırlanmış ifadeleri ile ihtiyacınız olacak çılgın kod miktarı ile karşılaştırın . Hata işleme, profil oluşturma, sorgu günlüğü zaten yerleşik ve çalışıyor.

$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, bağlama ve sorgu tanımında normal PDO ekleriyle karşılaştırın.

Başka bir örnek:

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

Böyle bir pratik durumu ele almak için PDO için bir örnek bulmak zor.
Ve çok garip ve büyük olasılıkla güvensiz olacak.

Yani, bir kez daha - sadece ham sürücü endişeniz değil, soyutlama sınıfı olmalı, sadece başlangıç ​​kılavuzundan aptalca örnekler için değil, aynı zamanda gerçek hayattaki sorunları çözmek için de faydalıdır.


20
mysql_*güvenlik açıklarını bulmayı çok kolaylaştırır. PHP birçok acemi kullanıcı tarafından kullanıldığından mysql_*, teorik olarak bir aksaklık olmadan bile pratikte aktif olarak zararlıdır.
Madara'nın Hayaleti

4
everything is parameterized and safe- parametrelendirilebilir, ancak işleviniz gerçek hazırlanmış ifadeler kullanmaz .
uınbɐɥs

6
Not under active developmentSadece bu '% 0.01' telafisi için nasıl ? Bu stand-still işleviyle bir şey oluşturursanız, mysql sürümünüzü bir yıl içinde güncelleyin ve çalışmayan bir sistemle tamamlayın, eminim ki bu '% 0.01'de aniden çok fazla insan var. Bunu söyleyebilirim deprecatedve not under active developmentyakından ilişkiliyim. Bunun için "layık bir neden" olmadığını söyleyebilirsiniz, ancak gerçek şu ki, seçenekler arasında bir seçim teklif edildiğinde, söyleyebildiğim no active developmentkadar kötü deprecatedmü?
Nanne

1
@MadaraUchiha: Güvenlik açıklarının ne kadar kolay olduğunu açıklayabilir misiniz? Özellikle aynı güvenlik açıklarının PDO veya MySQLi'yi etkilemediği durumlarda ... Çünkü bahsettiğiniz tek bir tanesinin farkında değilim.
ircmaxell

4
@ShaquinTrifonoff: Tabii, hazırlanmış ifadeler kullanmıyor. Ancak çoğu insanın MySQLi üzerinden önerdiği PDO da bunu yapmaz . Bu yüzden burada önemli bir etkisi olduğundan emin değilim. Yukarıdaki kod (biraz daha ayrıştırma ile) varsayılan olarak bir ifade hazırlarken PDO ne yapar ...
ircmaxell

97

Birçok neden var, ancak belki de en önemlisi, bu işlevlerin hazırlanmış ifadeleri desteklemedikleri için güvensiz programlama uygulamalarını teşvik etmesidir. Hazırlanan ifadeler SQL enjeksiyon saldırılarını önlemeye yardımcı olur.

mysql_*İşlevleri kullanırken , kullanıcı tarafından sağlanan parametrelerimysql_real_escape_string() . Yalnızca bir yerde unutursanız veya girdinin yalnızca bir kısmından kaçarsanız, veritabanınız saldırıya maruz kalabilir.

Bu tür programlama hatalarının hazırlanmasında PDOveya içinde hazırlanmış ifadelerin mysqlikullanılması daha zor hale getirecektir.


3
Ne yazık ki MySQLi_ * 'de değişken sayıda parametre iletme (örneğin, bir IN yan tümcesinde kontrol etmek için bir değer listesi iletmek istediğinizde) gibi zayıf destek, parametrelerin kullanılmamasını teşvik eder ve tam olarak aynı birleştirilmiş sorguların kullanılmasını teşvik eder MySQL_ * çağrılarını savunmasız bırakın.
Kickstart

5
Ancak, bir kez daha, güvensizlik mysql_ * fonksiyonlarının doğasında var olan bir problem değil, yanlış kullanım sorunudur.
Agamemnus

2
@Agamemnus Sorun, mysql_ * 'nin özellikle deneyimsiz programcılar için bu "yanlış kullanımı" uygulamayı kolaylaştırmasıdır. Hazırlanan ifadeleri uygulayan kütüphaneler bu tür bir hata yapmayı zorlaştırır.
Trott

75

Çünkü (diğer nedenlerin yanı sıra) giriş verilerinin dezenfekte edilmesini sağlamak çok daha zordur. Parametreli sorgular kullanırsanız, PDO veya mysqli ile olduğu gibi riskten tamamen kaçınabilirsiniz.

Örnek olarak, birisi "enhzflep); drop table users"kullanıcı adı olarak kullanabilir . Eski işlevler sorgu başına birden çok ifadenin yürütülmesine izin verir, böylece bu kötü adam gibi bir şey tüm tabloyu silebilir.

Biri mysqli PDO kullanacak olsaydı, kullanıcı adı sona erecekti "enhzflep); drop table users".

Görmek Bobby-tables.com .


10
The old functions will allow executing of multiple statements per query- hayır, yapmayacaklar. Bu tür bir enjeksiyon ext / mysql ile mümkün değildir - PHP ve MySQL ile bu tür bir enjeksiyonun tek yolu MySQLi ve mysqli_multi_query()işlevini kullanmaktır. Ext / mysql ve çıkışsız dizelerle mümkün olan tür enjeksiyon, ' OR '1' = '1erişilebilir olması amaçlanmamış veri tabanından veri çıkarmak gibi şeylerdir . Bazı durumlarda alt sorguları enjekte etmek mümkündür, ancak veritabanını bu şekilde değiştirmek hala mümkün değildir.
DaveRandom

64

Bu yanıt, kötü yazılmış PHP kullanıcı doğrulama kodunu atlamanın ne kadar önemsiz olduğunu, bu saldırıların nasıl (ve ne kullanarak) nasıl çalıştığını ve eski MySQL işlevlerinin güvenli bir hazır ifade ile nasıl değiştirileceğini ve temel olarak neden StackOverflow kullanıcılarının olduğunu göstermek için yazılmıştır. (muhtemelen çok sayıda temsilci ile) yeni kullanıcılara, kodlarını geliştirmek için sorular sorarak havlıyorlar.

İlk uzakta, bu test mysql veritabanı oluşturmak için çekinmeyin (mayın hazırlık denir):

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)

Bunu yaptıktan sonra PHP kodumuza geçebiliriz.

Aşağıdaki komut dosyasının bir web sitesindeki bir yöneticinin doğrulama işlemi olduğunu varsayalım (basitleştirilmiş ancak test için kopyalayıp kullanırsanı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 yasal görünüyor.

Kullanıcı bir giriş ve şifre girmelidir, değil mi?

Parlak, aşağıdakileri 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ını ve şifreyi deneyelim:

user: Fluffeh
pass: mypass

İnanılmaz! Hi-fives her yerde, kod doğru bir yönetici doğruladı. Mükemmel!

Pek değil. Kullanıcının zeki küçük bir kişi olduğunu varsayalım. 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, sadece süper korumalı yöneticiler bölümüne girmeme izin verdin, benimle yanlış bir kullanıcı adı ve yanlış bir şifre girmeliyim. Ciddi, bana inanmıyorsanız, verdiğim kod ile veritabanını oluşturun ve bu PHP kodunu çalıştırın - bir bakışta GERÇEKTEN kullanıcı adı ve şifre oldukça güzel doğrulamak gibi görünüyor.

Yani, cevap olarak, NEDEN BAĞLANIYORSUNUZ.

Şimdi, neyin yanlış gittiğine ve neden sadece süper yönetici-yarasa mağarasına girdiğime bakalım. Bir tahminde bulundum ve girdilerinize dikkat etmediğinizi ve bunları doğrudan veritabanına aktardığınızı varsaydım. Giriş gerçekten çalıştırdığınız sorguyu DEĞİŞTİRMEK bir şekilde inşa. Peki, ne olması gerekiyordu ve sonuçta ne oldu?

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

Sorgu budur, ancak değişkenleri kullandığımız gerçek girdilerle değiştirdiğimizde aşağıdakileri elde ederiz:

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

Önce "parolamı" nasıl yapılandırdığımı görün, böylece parola etrafındaki tek alıntıyı kapatabilir, sonra tamamen yeni bir karşılaştırma yapabilir miyim? Sonra sadece güvenlik için, tek bir alıntı aslında vardı kodunda beklendiği gibi kapalı olsun başka bir "dize" ekledi.

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

Tamam, neyin yanlış gittiğini nasıl düzeltebiliriz?

Bu klasik bir SQL enjeksiyon saldırısıdır. Bu konudaki en basitlerden biri. Saldırı vektörleri ölçeğinde, bu bir tanka saldıran ve kazanan bir yürümeye başlayan çocuk.

Peki, kutsal yönetici bölümünüzü nasıl koruyabilir ve güzel ve güvenli hale getirebiliriz? Yapılacak ilk şey, gerçekten eski ve kullanımdan kaldırılmış mysql_*işlevleri kullanmayı bırakmak olacaktır . Biliyorum, çevrimiçi bulduğunuz bir öğreticiyi takip ettiniz ve işe yarıyor, ama eski, modası geçmiş ve birkaç dakika içinde, bir ter kırmadan çok geçtim.

Şimdi, mysqli_ veya PDO kullanma konusunda daha iyi seçeneklere sahipsiniz . Ben şahsen 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 profesyonelin aleyhte olanlardan daha ağır bastığını görüyorum. İster bağlantı dizesini değiştirerek, ister MySQL veya Oracle veya hemen hemen kanlı bir şey kullanıyor olun, birden fazla veritabanı motorunda taşınabilir, kullanmak istediğimiz tüm fantezi özelliklere sahiptir ve güzel ve temizdir. Temizlemeyi 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 fark, daha fazla mysql_*fonksiyon olmamasıdır . Her şey bir PDO nesnesi aracılığıyla yapılır, ikincisi, hazırlanmış bir ifade kullanır. Şimdi, sorduğunuz önceden yazılmış bir ifade nedir? Veritabanını bir sorgu çalıştırmadan önce, çalıştıracağımız sorgunun ne olduğunu söylemenin bir yolu. Bu durumda, veritabanına söyle: "Merhaba, ben id, userid ve userid bir değişken ve pass da bir değişken olduğu tablo kullanıcılarından geçmek isteyen bir select deyimi çalıştıracağım."

Ardından, execute deyiminde, veritabanına şimdi beklediği tüm değişkenleri içeren bir dizi geçiririz.

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

user: bob
pass: somePass

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

Nasıl olur:

user: Fluffeh
pass: mypass

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

Şimdi, küçük doğrulama sistemimizi geçmek için akıllı bir arkadaşın gireceği verileri deneyelim:

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

Bu sefer şunları elde ediyoruz:

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

Bu yüzden soru gönderirken bağırıyorsunuz - çünkü insanlar kodunuzun denemeden bile atlanabileceğini görebilirler. Lütfen kodunuzu geliştirmek, daha güvenli hale getirmek ve güncel işlevleri kullanmak için bu soruyu ve cevabı kullanın.

Son olarak, bu bunun MÜKEMMEL kod olduğu anlamına gelmez. Geliştirmek için yapabileceğiniz çok daha fazla şey var, örneğin karma şifreleri kullanın, veritabanında hassas bilgileri sakladığınızda, düz metinde saklamayın, birden fazla doğrulama seviyesine sahip olduğunuzdan emin olun - ancak gerçekten, sadece eski enjeksiyon eğilimli kodunuzu buna değiştirirseniz, iyi kod yazma yolunda iyi olacaksınız - ve bu kadar ilerlemiş olduğunuz ve hala okuduğunuz gerçeği bana sadece bu tür bir uygulama yapmayacağınıza dair bir umut duygusu veriyor web sitelerinizi ve uygulamalarınızı yazarken koddan çıkabilirsiniz, ancak dışarı çıkıp daha önce bahsettiğim diğer şeyleri ve daha fazlasını araştırabilirsiniz. Zar zor çalışan en temel kodu değil, yapabileceğiniz en iyi kodu yazın.


2
Cevabınız için teşekkür ederim! + 1'imi al! Kendi mysql_*başına güvensiz olmadığını belirtmek gerekir , ancak kötü öğreticiler ve uygun bir ifade eksikliği API hazırlamak yoluyla güvensiz kodu teşvik eder.
Madara'nın Hayaleti

2
şifrelenmemiş şifreler, oh dehşet! = oP Aksi takdirde ayrıntılı açıklama için +1.
cryptic ツ

33

MySQL uzantısı üçünün en eskisidir ve geliştiricilerin MySQL ile iletişim kurmak için kullandıkları orijinal yoldur. Bu uzantı, hem PHP'nin hem de MySQL'in daha yeni sürümlerinde yapılan iyileştirmeler nedeniyle diğer iki alternatifin lehine kaldırılıyor .

  • 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 fonksiyon odaklı hem de nesne odaklı bir arayüz sunar ve birkaç başka şık şey de yapar.

  • PDO , MySQL, PostgreSQL, SQLite, MSSQL vb. Gibi büyük veritabanı erişim uzantılarına yayılmış işlevselliğin çoğunu birleştiren bir API sunar. Arabirim, programcının veritabanı bağlantıları, sorgular ve sonuç kümeleri ve düşük düzey sürücüler veritabanı sunucusuyla iletişim ve kaynak işleme gerçekleştirir. PDO'ya çok fazla tartışma ve çalışma gidiyor ve modern, profesyonel kodda veritabanlarıyla çalışmak için uygun yöntem olarak kabul ediliyor.


21

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

Mysqli uzantısının birkaç faydası vardır, mysql uzantısı üzerindeki önemli geliştirmeler şunlardır:

  • Nesne yönelimli arayüz
  • Hazırlanan İfadeler için Destek
  • Birden Çok İfade Desteği
  • İşlem Desteği
  • Gelişmiş hata ayıklama özellikleri
  • Yerleşik sunucu desteği

Kaynak: MySQLi'ye genel bakış


Yukarıdaki cevaplarda açıklandığı gibi, mysql için alternatifler mysqli ve PDO'dur (PHP Veri Nesneleri).

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

Hem MySQLi hem de PDO PHP 5.0'da, MySQL ise PHP 3.0'dan önce tanıtıldı. Unutulmaması gereken nokta, MySQL'in PHP5.x sürümüne dahil edilmesidir, ancak sonraki sürümlerde kullanımdan kaldırılmıştır.


2
Cevabınız çok uzun, gerçek özet ise "mysql ext artık yok". Hepsi bu
Common Sense

1
@YourCommonSense Benim cevabım mysqli neden mysql yerini aldı. Mesele Mysqli'nin bugün var olduğunu söylemek değildir, bu yüzden kullanın .. Herkes bunu biliyor!
Ani Menon

1
Peki, kimsenin neden mysqli'nin mysql yerine geçtiğini sormaması dışında, bu soruyu da cevaplamıyor. Mysqli'nin neden tanıtıldığını cevaplıyor. Ancak mysql ve mysqli'nin neden paralel olarak yaşamalarına izin verilmediğini açıklamıyor
Sizin Common Sense

@YourCommonSense Ayrıca OP'nin sorusu "Sitemde çalışıyor olsalar bile neden başka bir şey kullanmalıyım?" ve bu yüzden değişiklikleri ve gelişmeleri işaret ettim. Uzun olan diğer cevaplara bakabilirsiniz, bu yüzden özetlemeliyim diye düşündüm.
Ani Menon

6

mysql_*Mysqli veya PDO kullanarak hemen hemen tüm fonksiyonları tanımlamak mümkündür . Bunları eski PHP uygulamanızın üzerine ekleyin ve PHP7 üzerinde çalışacaktır. Buradaki çözümüm .

<?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;
}

Çözümünüz için bağlantı göstermek yerine, lütfen bunları yanıt olarak buraya ekleyin.
amarnath

1

Buna benzer gibidir işlevler mysql_connect(), mysql_query()türü artık kullanımda değil PHP yani (PHP 4) fonksiyonları ve önceki sürüm bulunmaktadır.

Bunların yerini mysqli_connect(), mysqli_query()en son PHP5'te olduğu gibi alır.

Hatanın arkasındaki sebep budur.


2
PHP 5 2 yıldan uzun süredir en yeni sürüm değil.
Madara'nın Hayaleti

1

MySQL PHP 5.5.0'da kullanımdan kaldırıldı ve PHP 7.0.0'da kaldırıldı. Büyük ve eski bir uygulama için, her bir işlevi aramak ve değiştirmek zordur.

Aşağıdaki kodların her biri için bir sarmalayıcı işlevi oluşturarak MySQL işlevlerini kullanabiliriz. Buraya Tıkla


-9

mysql_ * işlevleri , daha iyi işlevlerin ve kod yapılarının geliştirildiği düşünüldüğünde ( PHP 5.5'ten itibaren ) kullanımdan kaldırılmıştır . Fonksiyonun kullanımdan kaldırılması, performans ve güvenlik açısından iyileştirilmesi için daha fazla çaba harcanmayacağı anlamına gelir , bu da geleceğin daha az kanıtı olduğu anlamına gelir. .

Daha fazla nedene ihtiyacınız varsa:

  • mysql_ * fonksiyonları hazırlanmış ifadeleri desteklemez.
  • mysql_ * işlevleri parametrelerin bağlanmasını desteklemez.
  • mysql_ * işlevleri Nesne Tabanlı Programlama için işlevsellikten yoksundur.
  • liste devam ediyor ...

18
Bu cevap eski. Ayrıca, zaten var olan cevaplara yararlı bir şey eklemiyor.
Sizin Common Sense
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.