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


Kullanılmaması gereken teknik nedenler nelerdir? mysql_* fonksiyonlar? (Örneğin. mysql_query(), mysql_connect() veya mysql_real_escape_string())?

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

Sitemde çalışmıyorlarsa neden gibi hatalar alıyorum

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


2196
2017-10-12 13:18


Menşei


Olması gereken bir hata: Önemli hata: Yakalanmayan Hata: tanımlanmamış bir işlev çağrısı mysql_connect () ... - Bimal Poudel
Tek başına eskimiş, onlardan kaçınmak için yeterli sebeptir - Sasa1234


Cevaplar:


MySQL uzantısı:

  • Aktif gelişim altında değil
  • resmi olarak kullanımdan kaldırıldı PHP 5.5'ten itibaren (Haziran 2013'te yayınlanmıştır).
  • Olmuştur çıkarıldı Baştan sona PHP 7.0'dan itibaren (Aralık 2015'te yayınlanmıştır)
    • Bu şu anlama gelir: 31 Ara 2018 PHP'nin desteklenen herhangi bir sürümünde mevcut olmayacaktır. Şu anda sadece alır güvenlik güncellemeler.
  • Bir OO arayüzü eksik
  • Desteklemiyor:
    • Tıkanmasız, 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 5.7'de MySQL 5.6'da gereklidir)
    • MySQL 5.1'deki tüm işlevler

Kullanımdan kaldırıldığından, kodu kullanmak kodunuzu daha az kanıtlamaktadır.

Hazırlanan ifadeler için destek eksikliği, dış veriden kaçmak ve alıntılamak için daha net, daha az hataya eğilimli bir yöntem sağladıkları için ayrı bir işlev çağrısı ile manüel olarak kaçmaktan daha önemlidir.

Görmek SQL uzantıları karşılaştırması.


1814
2018-01-01 11:52



Tek başına eskimiş, onları önlemek için yeterlidir. Bir gün orada olmayacaklar ve onlara güvenirsen mutlu olmazsın. Gerisi, eski uzantıları kullananların insanları öğrenmekten alıkoyan şeylerin sadece bir listesi. - Tim Post♦
Deprecation, herkesin düşündüğü gibi görünen sihirli mermi 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 olduğumuzda, yapacağız. - Lightness Races in Orbit
@LightnessRacesinOrbit - Deprecation sihirli bir mermi değil, "Bu berbatın farkındayız, bu yüzden bunu daha uzun süre desteklemeyeceğiz" diyor. Daha iyi gelecekteki kod yazımına sahip olmak, kullanımdan kaldırılan özelliklerden uzaklaşmak için iyi bir neden olsa da, yalnızca bir tanesi (hatta ana olan) değildir. Araçları değiştirin çünkü daha iyi araçlar vardır, zorlandığınız için değil. (Ve yeni araçları öğrenmek zorunda kalmadan önce araçları değiştirmek zorunda kalıyorsunuz çünkü kodunuz çalışmayı durdurdu ve düzelmeye ihtiyaç duyuyordu. Bu, yeni araçları öğrenmenin en kötü zamanıdır). - Quentin
Görmediğim bir şey, hazırlanan ifadelerin eksikliğinden bahsetti. Her zaman bir açıklama yaparsanız, bir şey MySQL daemon bunu anlayabilmek için derlemek zorundadır. Bu API ile, bir döngüde aynı sorgunun 200.000'ini yayınlarsanız, bu sorunun anlaşılması için MySQL için sorgulamanın 200.000 katı olması gerekir. Hazırlanan ifadelerle, bir kez derlenmiş ve sonra değerleri derlenmiş SQL'e parametrelendirilmiştir. - Goldentoa11
@symcbean, kesinlikle yapar değil hazırlanan ifadeleri destekler. Aslında bu, kullanımdan kaldırılmasının ana nedenidir. Hazırlanan (kullanımı kolay) ifadeler olmadan, mysql uzantısı genellikle SQL enjeksiyon saldırılarına mağdur olur. - rustyx


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

mysql_* İşlevler çok popülerdi, ancak artık kullanımı teşvik edilmiyor. Belge ekibi veritabanı güvenlik durumunu tartışıyor ve kullanıcıların yaygın olarak kullanılan ext / mysql uzantısından uzaklaşmasını sağlıyor. php.internals: kullanım dışı / mysql).

Ve daha sonra PHP geliştirici ekibi üretme kararını aldı E_DEPRECATED Kullanıcılar, MySQL'e bağlandığında hatalar mysql_connect(), mysql_pconnect() veya örtülü bağlantı işlevselliği ext/mysql.

ext/mysql oldu PHP 5.5'ten itibaren resmi olarak kullanımdan kaldırıldı ve olmuştur PHP 7'den kaldırıldı.

Kırmızı Kutuyu Görüyor musunuz?

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

Niye ya


Uzaklaşmak ext/mysql sadece güvenlik hakkında değil, aynı zamanda MySQL veritabanının tüm özelliklerine erişme hakkındadır.

ext/mysql için inşa edildi MySQL 3.23 ve o zamandan bu yana, sadece bu eski sürümle uyumluluğu koruyarak, kodun bakımını biraz daha zor hale getiren çok az ekleme oldu. Tarafından desteklenmeyen eksik özellikler ext/mysql Dahil etmek: (PHP kılavuzundan).

Kullanmama nedeni mysql_* fonksiyon:

  • Aktif gelişim altında değil
  • PHP 7'den kaldırıldı
  • Bir OO arayüzü eksik
  • Engelleme olmayan, eşzamansız sorguları desteklemiyor
  • Hazırlanan ifadeleri desteklemiyor veya parametreli sorgular
  • Saklı yordamları desteklemiyor
  • Birden çok ifadeyi desteklemiyor
  • Desteklemiyor işlemler
  • MySQL 5.1'deki tüm işlevleri desteklemiyor

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

Hazırlanan ifadeler için destek eksikliği, dış veriden kaçmak ve alıntılamak için daha net, daha az hataya eğilimli bir yöntem sağladıkları için ayrı bir işlev çağrısı ile manüel olarak kaçmaktan daha önemlidir.

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


Kullanımdan kaldırılma uyarılarını iptal etme

Kod dönüştürülürken MySQLi/PDO, E_DEPRECATED ayarlarla hatalar bastırılabilir error_reporting içinde php.ini hariç tutmak E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

Bunun da gizleneceğini unutmayın. diğer kullanım dışı bırakma uyarılarıBununla birlikte, MySQL dışındaki şeyler için olabilir. (PHP kılavuzundan)

Makale PDO vs MySQLi: Hangisini Kullanmalı? tarafından Dejan Marjanovic seçim yapmanıza yardımcı olacak.

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


Basit ve kısa bir PDO eğitimi


S. Aklımdaki ilk soru: '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. ”

alt text


MySQL'e bağlanma

İle mysql_* işlev ya da eski yolu söyleyebiliriz (PHP 5.5 ve üstü kullanımdan kaldırılmış)

$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 şey yaratmak. PDO nesne. Yapıcı, veritabanı kaynağını belirlemek için parametreleri kabul eder PDOkurucusu çoğunlukla dört parametre alır DSN (veri kaynağı adı) ve isteğe bağlı olarak username, password.

Burada herşeyi bildiğinizi düşünüyorum DSN; bu yeni PDO. bir DSN temelde söyleyen bir dizi seçenek PDO hangi sürücüyü kullanacak ve bağlantı detayları. Daha fazla referans için, kontrol edin PDO MySQL DSN.

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

Not: Ayrıca kullanabilirsiniz charset=UTF-8ama bazen bir hataya sebep olur, bu yüzden kullanmak daha iyidir utf8.

Herhangi bir bağlantı hatası varsa, bir PDOException ele alınabilecek nesne Exception Daha ileri.

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

Dördüncü parametreye bir dizi olarak çeşitli sürücü seçeneklerini de iletebilirsiniz. Ben koyar parametreyi geçmesini öneririm PDO istisna moduna. Çünkü bazı PDO sürücüler yerel hazırlanmış ifadeleri desteklemez PDO hazırlığın emülasyonunu yapar. Ayrıca bu öykünmeyi manuel olarak etkinleştirmenizi sağlar. Yerel sunucu tarafında hazırlanmış ifadeleri kullanmak için, açıkça ayarlamanız gerekir. false.

Diğerinde etkin olan emülasyonu hazırlamak MySQLvarsayılan olarak sürücü, ancak öykünme hazırlamak kullanmak için kapatılmalıdır PDO güvenli bir şekilde.

Daha sonra emülasyonu hazırlamanın neden kapatıldığını açıklayacağım. Nedeni bulmak için lütfen kontrol edin bu gönderi.

Eski bir sürümünü kullanıyorsanız sadece kullanılabilir MySQL Ben tavsiye etmiyorum ki.

Aşağıda, bunu nasıl yapabileceğinize dair 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ından sonra özellikleri ayarlayabilir miyiz?

EvetAyrıca, PDO yapımından sonra bazı özellikleri ayarlayabiliriz. setAttribute yöntem:

$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 çok daha kolay PDO göre mysql_*.

Kullanırken yaygın bir uygulama mysql_* geçerli:

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

OR die() hatayı işlemek için iyi bir yol değil çünkü biz die. Komut dosyası aniden sona erecek ve ardından genellikle son kullanıcılarınıza göstermek istemediğiniz bir hatayı yankılayacak ve kanlı korsanların şemanızı keşfetmesine izin verecektir. Alternatif olarak, dönüş değerleri mysql_* fonksiyonlar genellikle aşağıdakiler ile birlikte kullanılabilir MySQL Hatası() hataları işlemek için.

PDO daha iyi bir çözüm sunar: istisnalar. Yaptığımız her şey PDO sarılmış bir try-catch blok. Zorlayabiliriz PDO Hata modu özniteliğini ayarlayarak üç hata modundan birine. Üç hata işleme modu aşağıdadır.

  • PDO::ERRMODE_SILENT. Sadece hata kodlarını ayarlıyor ve hemen hemen aynı davranıyor. mysql_* her bir sonucu kontrol etmeniz gereken ve daha sonra baktığınız $db->errorInfo(); hata ayrıntılarını almak için.
  • PDO::ERRMODE_WARNING Yükseltmek 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 yükseltilen bir hatayı temsil eder. Sen atmamalısın PDOException kendi kodunuzdan. Görmek İstisnalar PHP'deki istisnalar hakkında daha fazla bilgi için. Çok benziyor or die(mysql_error());yakalanmadığı zaman. Ama aksine or die(), PDOException Bunu yapmayı seçerseniz yakalanabilir ve incelikle 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 içine sarılabilirsin try-catch, aşağıdaki gibi:

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 uğraşmak zorunda değilsin try-catch şimdi. Uygun olan herhangi bir zamanda onu yakalayabilirsiniz, ama kesinlikle kullanmanızı tavsiye ederim try-catch. Ayrıca, onu çağıran fonksiyonun dışında yakalamak daha mantıklı olabilir. PDO şey:

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, tarafından idare edebilirsiniz or die() ya da biz söyleyebiliriz mysql_*ama gerçekten farklı olacak. Üretimde tehlikeli hata mesajlarını çevirerek gizleyebilirsiniz. display_errors off ve sadece hata günlüğünü okuyorsunuz.

Şimdi, yukarıdaki tüm şeyleri okuduktan sonra, muhtemelen düşünürsünüz: sadece basit bir şekilde yalpalamaya başlamak istediğimde SELECT, INSERT, UPDATEveya DELETE ifadeleri? Endişelenme, işte gidelim:


Veri Seçimi

PDO select image

Yani ne yapıyorsun mysql_* geçerli:

<?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 PDObunu şöyle yapabilirsin:

<?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 gibi bir yöntem kullanıyorsanızquery()), bu yöntem bir PDOStatement nesne. Yani sonucu almak istiyorsanız, yukarıdaki gibi kullanın.

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

PDO Verilerinde, ->fetch(), deyim işleminizin bir yöntemi. Getirmeyi çağırmadan önce, en iyi yaklaşım PDO'ya verilerin getirilmesini nasıl istediğinizi anlatıyor olabilir. Aşağıdaki bölümde bunu açıklarım.

Getirme Modu

Kullanımı not PDO::FETCH_ASSOC içinde fetch() ve fetchAll() Yukarıdaki kod. Bu söyler PDO Satırları alan adları ile ilişkilendirilmiş bir dizi olarak döndürmek için. Birbirini açıklayacağım birçok başka getirme modu da var.

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

 $stmt->fetch(PDO::FETCH_ASSOC)

Yukarıdakilerde 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 dizilmiş bir dizi döndürür
  • PDO::FETCH_BOTH (varsayılan): sonuç kümenize döndürülmüş olarak hem sütun adı hem de 0 dizinli sütun numarası tarafından dizine eklenmiş bir dizi döndürür

Daha fazla seçenek var! Hepsini okumak PDOStatement Belgeleri al..

Satır sayımı alınıyor:

Kullanmak yerine mysql_num_rows iade edilen satır sayısını almak için PDOStatement ve yap rowCount(), sevmek:

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

Eklemek ve Güncelleştirmek veya Silmek

Insert and update PDO image

Ne yapıyoruz mysql_* işlevi:

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

Ve pdoda, aynı şey şu şekilde yapılabilir:

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

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

Ekleme ve silme daha sonra ele alınacaktır.

Yukarıdaki yöntem, yalnızca sorguda değişken kullanmıyorsanız kullanışlıdır. Ama bir sorguda bir değişken kullanmanız gerektiğinde, yukarıdaki gibi hiç denemeyin. hazırlanan deyim veya parametreli deyim olduğunu.


Hazırlanmış İfadeler

S. Hazırlanmış bir ifade nedir ve neden onlara ihtiyacım var?
A. Hazırlanan bir deyim, yalnızca sunucuya veri göndererek, birden çok kez yürütülebilen bir önceden derlenmiş SQL deyimidir.

Hazırlanan bir ifadeyi kullanmanın tipik iş akışı aşağıdaki gibidir (Vikipedi üç 3 noktadan alıntı):

  1. HAZIRLAMA: Açıklama şablonu uygulama tarafından oluşturulur ve veritabanı yönetim sistemine (DBMS) gönderilir. Belirli değerler belirsiz bırakılır, parametreler, yer tutucular veya bağlama değişkenleri olarak adlandırılır (etiketli ? altında):

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

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

  3. gerçekleştirmek: Daha sonraki bir zamanda, uygulama parametreler için değerleri (veya bağlar) verir ve DBMS ifadesini yürütür (muhtemelen bir sonuç döndürür). Uygulama, ifadeyi istediği sayıda farklı değerlerle çalıştırabilir. Bu örnekte, ilk parametre için 'Ekmek' verebilir ve 1.00ikinci parametre için.

SQL'inizde yer tutucuları dahil ederek hazırlanmış bir deyimi kullanabilirsiniz. Temelde üç kişi yer tutucusuzdur (bunu yukarıdaki ile değişkeni denemeyin), biri isimsiz yer tutucuları, biri de yer tutucu yer tutucuları ile.

S. Öyleyse, şimdi yer tutucuları nelerdir ve bunları nasıl kullanırım?
A. Adlandırılmış yer tutucuları. Öncelikle soru işaretleri yerine, iki nokta üst üste tanımlayıcı adları kullanın. İsim yer tutucudaki konum / sipariş değeri umurumda değil:

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

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

Ayrıca bir yürütme dizisi kullanarak da bağlayabilirsiniz:

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

İçin başka güzel bir özellik OOP arkadaşlar, adlandırılmış yer tutucuların, özelliklerin adlandırılmış alanlarla eşleştiğini varsayarak, doğrudan veritabanınıza nesne ekleme yeteneğine sahip olmaları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, isimsiz yer tutucuları nelerdir 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ıdakilerde, bunları görebilirsiniz ? isim sahibi gibi bir isim yerine. Şimdi ilk örnekte çeşitli yer tutuculara değişkenler atarız ($stmt->bindValue(1, $name, PDO::PARAM_STR);). Ardından, bu yer tutuculara değerler atar ve ifadeyi uygularız. İkinci örnekte, ilk dizi öğesi ilk gider ? ve ikincisine ikinci ?.

NOT: İçinde adsız yer tutucuları bize geçirdiğimiz dizideki elemanların uygun düzenine dikkat etmeliyiz PDOStatement::execute() yöntem.


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ı kontrol et PDO, SQL enjeksiyonunu önlemek için yeterli ifadeler hazırladı mı? tarafından ircmaxell. Ayrıca, onun cevabından biraz 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 /*"));

1163
2017-10-12 13:28



Yukarıda okunan neyin makul bir şekilde belirtilmesi gerekir: hazırlanan ifade, herhangi bir anlamlı kullanımını IN (...) construct. - Eugen Rieck
@Amine, Hayır, öyle değil! :] Süre NullPoiиteя gerçekten yazmanın harika bir işini yaptı, bu kesinlikle iyi bir okuma değil, çünkü uzun yol. Eminim, bu 10 ziyaretçiden 8'i atlayacaktır. Ve ayrıca açıklamanız da var, neden bu cevap en çok oylanmadı. bir tl;drbaşlangıçta bölüm iyi bir fikir olurdu, bence. - trejder
Soru, "Neden PHP'de mysql_ * işlevlerini kullanmamalı" idi. Bu cevap, etkileyici ve yararlı bilgilerle dolu olsa da, WAY'ı kapsam dışı bırakıyor ve @trejder şöyle diyor: - 10 kişinin 8'i bu bilgileri kaçırmayacak çünkü 4 saat çalışmaz o. Bu çok daha değerli ve daha kesin sorulara cevap olarak kullanıldı. - Alex McMillan
Persoanlly mysqli ve PDO'yu tercih ederim. Ama ölmek için istisna alternatifini denedim function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx(); İstisnalar atmak için çalışır. - kuldeep.kamboj


Öncelikle, herkese verdiğimiz standart yorum ile başlayalım:

Lütfen kullanma mysql_* yeni kodda işler. Artık korunmuyorlar ve resmi olarak kullanımdan kaldırıldı. Bakın kırmızıkutu? Hakkında bilgi al hazırlanan ifadeler yerine ve kullan PDO veya MySQLi - Bu makale hangisine karar vermenize yardımcı olacak. PDO'yu seçerseniz, işte iyi bir öğretici.

Hadi bunu, cümle ile cümle, ve açıklayalım:

  • Artık korunmuyor ve resmi olarak kullanımdan kaldırılıyor

    Bu, PHP topluluğunun yavaş yavaş bu çok eski işlevler için desteği düşürdüğü anlamına gelir. PHP'nin gelecekteki (yeni) versiyonunda bulunmayacaklar! Bu işlevlerin sürekli kullanımı, kodunuzu (çok da değil) uzak gelecekte bozabilir.

    YENİ! - ext / mysql şimdi 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ı desteklemiyor hazırlanan ifadeler(diğer şeylerin yanı sıra) karşı çok etkili bir karşı önlem SQL Enjeksiyonu. MySQL'e bağımlı uygulamalarda, saldırganların komut dosyasına erişmesine ve gerçekleştirmesine olanak veren çok ciddi bir güvenlik açığını giderdi olası bir sorgu veritabanında.

    Daha fazla bilgi için bakınız PHP'de SQL enjeksiyonunu nasıl önleyebilirim?

  • Kırmızı Kutuyu Görüyor musunuz?

    Herhangi birine gittiğinde mysql işlev kılavuzu sayfası, artık kullanılmaması gerektiğini açıklayan kırmızı bir kutu görüyorsunuz.

  • PDO veya MySQLi'yi kullanın

    Daha iyi, daha sağlam ve iyi inşa edilmiş alternatifler var. PDO - PHP Veritabanı Nesnesiveritabanı etkileşimine tam bir OOP yaklaşımı sunar ve MySQLiMySQL özel bir gelişme.


280
2017-12-24 23:30



Bir şey daha var: PHP'de hala tek bir nedenden ötürü bu işlevin var olduğunu düşünüyorum - eski, modası geçmiş ama hala CMS, e-ticaret, bülten panosu sistemleri vb. İle uyumluluk. Son olarak, bu işlem kaldırılacak ve yeniden yazmanız gerekecektir. uygulama... - Kamil
@Kamil: Bu doğru, ama kullanmamanın sebebi de bu değil. Bunu kullanmamanın sebebi antik, güvensiz, vb. - Madara Uchiha♦
@Mario - PHP devlerinin bir süreci vardır ve sadece 5.5'ten itibaren resmi olarak kullanımdan kaldırılan ext / mysql lehine oy verdiler. Artık varsayımsal bir sorun değil. - SDC
PDO veya MySQLi gibi kanıtlanmış bir teknikle birkaç ekstra satır eklemek, PHP'nin her zaman sunduğu kullanım kolaylığını sağlar. Geliştiricinin iyiliği için, herhangi bir öğreticide bu tanrıça mysql_ * işlevlerini görmenin dersten gerçekten uzaklaştığını ve OP'den bu tür bir kodun 10 yıl önce soooo olduğunu söylemesi gerektiğini sorar. öğreticinin alaka düzeyi de! - FredTheWebGuy
Yanıtın ne denilebileceği sorusu: Hazırlanmış ifade, IN (...) construct. - Eugen Rieck


Kullanım kolaylığı

Analitik ve sentetik nedenler daha önce belirtilmiştir. Yeni gelenler için, tarihli mysql_ işlevlerini kullanmayı bırakmanın daha önemli bir yolu var.

Çağdaş veritabanı API'ları sadece Daha kolay kullanmak.

Çoğunlukla bağlı parametreler kodu basitleştirebilir. Ve birlikte mükemmel öğreticiler (yukarıda görüldüğü gibi) geçiş PDO aşırı zorlu değil.

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

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

kullanma <pdo_mysql.php> eski mysql_ işlevlerinden az çaba. Ekliyor pdo_ onların yerine geçen fonksiyon paketleyicileri mysql_ muadilleri.

  1. basitçe include_once("pdo_mysql.php"); Veritabanlarıyla etkileşime girmesi gereken her bir komut dosyasında.

  2. Kaldır mysql_ işlev öneki her yerde ve bununla 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 çoğunlukla aynı şekilde 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à.
Kodun kullanma PDO.
Şimdi gerçek zamanı yararlanmak o.

Bağlanan parametrelerin kullanımı kolay olabilir

Sadece daha az güvensiz bir API'ye ihtiyacınız var.

pdo_query() Bağlı parametreler için çok kolay destek ekler. Eski kodu dönüştürmek basittir:

Değişkenlerinizi SQL dizgesinden dışarı taşıyın.

  • Bunları virgülle sınırlanmış fonksiyon parametreleri olarak ekleyin. pdo_query().
  • Soru işaretlerini yerleştir ? değişkenlerin daha önce bulunduğu yer tutucuları olarak.
  • Kurtulmak ' Önceden kapalı dize değerleri / değişkenleri olan tek tırnaklar.

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

Çoğu zaman, dize değişkenleri yalnızca SQL'e enterpolasyon uygulanmaz, ancak 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")

İle ? uygulayan yer tutucuları 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)

Pdo_ * 'in hala izin verdiğini unutmayın. ya da.
Sadece bir değişkenden kaçma ve aynı sorguya bağlayın.

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

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

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

Çok sadelik. Ancak, neden kurtulmak isteyebileceğinizle ilgili daha fazla yeniden yazma önerisine ve teknik nedenlere dönelim. mysql_ve kaçmak.

Herhangi bir okulu düzeltin veya kaldırın sanitize() fonksiyon

Tümünü dönüştürdüğünüzde mysql_ çağırır pdo_query bağlı param ile, tüm gereksiz kaldırmak pdo_real_escape_string çağırır.

Özellikle, herhangi bir düzeltmeniz gerekir sanitize veya clean veya filterThis veya clean_data Bir formda veya diğer bir tarihte tarihli eğiticiler tarafından reklamı yapılan işlevler:

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

Buradaki göz kamaştırıcı böceklerin çoğu, belgelerin eksikliğidir. Daha da önemlisi, filtreleme sırası tam olarak yanlış sıradaydı.

  • Doğru sıralama şöyle olurdu: stripslashes en içten arama olarak trim, sonradan strip_tags, htmlentities çıktı içeriği için ve sadece son olarak _escape_string Uygulamanın doğrudan SQL intersparsing'i alması gerektiğinden.

  • Ama ilk adım olarak sadece Kurtulmak _real_escape_string aramak.

  • Geri kalanını korumak zorunda kalabilirsiniz. sanitize() Veritabanınız ve uygulama akışınız HTML bağlamında güvenli dizeler olmasını bekliyorsa, şimdilik işlev. Bunun, yalnızca bundan sonra çıkarılan HTML’ye uyguladığı bir yorum ekleyin.

  • String / value işleme, PDO'ya ve parametrelenmiş ifadelerine verilir.

  • Herhangi bir söz varsa stripslashes() sanitize fonksiyonunuzda, daha yüksek bir gözetim göstergesi olabilir.

    Magic_quotes üzerindeki tarihi not. Bu özellik haklı olarak kullanımdan kaldırılmıştır. Genellikle hatalı olarak hatalı şekilde resmedilir güvenlik Ancak özelliği. Fakat magic_quotes, tenis topları beslenme kaynağı olarak başarısız olduğu için başarısız bir güvenlik özelliğidir. Bu onların amacı değildi.

    PHP2 / FI'deki orijinal uygulama, sadece "Form verilerinin msql sorgularına doğrudan aktarılmasını kolaylaştırmak için teklifler otomatik olarak çıkarılacaktır.". İle kullanmak için kesinlikle güvenli MsqlBu sadece ASCII'yi destekledi.
      Sonra PHP3 / Zend MySQL için magic_quotes'ı tekrar ekledi ve yanlış belgelendi. Ama aslında sadece bir kolaylık özelliğigüvenlik için değil.

Hazırlanan ifadeler nasıl farklıdır?

Dize değişkenlerini SQL sorgularına karıştırdığınızda, takip etmeniz yalnızca daha karmaşık olmaz. MySQL'in kod ve verileri tekrar ayrıştırması da gereksiz bir çaba.

SQL enjeksiyonları sadece ne zaman veri kodlara sızıyor bağlamı. Bir veritabanı sunucusu daha sonra, PHP'nin sorgulama cümleleri arasında orijinal olarak yapıştırılmış değişkenlerin yerini tespit edemez.

Bağımlı parametrelerle, PHP kodunuzda SQL kodunu ve SQL bağlam değerlerini ayırırsınız. Ancak sahnelerin ardında tekrar karıştırılmıyor (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 vurgularken 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.

Parametre ciltlemenin hala tek bir sihirli çözüm olmadığına dikkat edin. herşey SQL enjeksiyonları. Veri / değerler için en yaygın kullanımı ele alır. Ancak, sütun adı / tablo tanımlayıcılarını beyaz listeye ekleyemez, dinamik yan tümce oluşturmaya veya yalnızca düz dizi değer listelerine yardımcı olamaz.

Hibrid PDO kullanımı

Bunlar pdo_* sarıcı işlevleri, kodlama dostu bir dur-boşluk API'sı oluşturur. (Bu oldukça fazla MYSQLI idiosyncratic işlev imza vardiyası olmasaydı olabilirdi. Onlar da gerçek PDO'yu çoğu zaman açığa çıkarırlar.
Yeniden yazma, yeni pdo_ işlev adlarını kullanmaya son vermek zorunda değil. Her bir pdo_query () yöntemini bir düz bir $ pdo-> prepare () -> execute () çağrısına tek tek geçiş yapabilirsiniz.

Ancak 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 yineleme ile değiştirilebilir:

foreach ($result as $row) {

Ya da daha iyi bir doğrudan ve tam dizi alma:

$result->fetchAll();

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

Diğer seçenekler

Yani bu umarım bir şekilde görselleştirdi pratik nedenleri ve düşmeye değer bir yol mysql_.

Sadece geçiş yapmak  oldukça kesmiyor. pdo_query() aynı zamanda sadece bir ön yüzdür.

Ayrıca, parametrenin ciltlenmesini sağlamazsanız veya daha güzel API'den başka bir şey kullanamazsanız, anlamsız bir anahtardır. Umarım yeni gelenlere cesaret kırmayacak kadar basit resmedilmiştir. (Eğitim genellikle yasaklamadan daha iyi çalışır.)

En basit olanı-olabilecek-olabilecek-iş kategorisine uygun olsa da, yine de çok deneysel bir koddur. Sadece hafta sonu yazdım. Ancak birçok alternatif var. Sadece google PHP veritabanı soyutlaması ve biraz göz atın. Böyle görevler için her zaman çok sayıda mükemmel kütüphane var ve olacak.

Veritabanı etkileşiminizi daha da basitleştirmek istiyorsanız, haritacılar gibi Paris / Idiorm denemeye değer. Artık hiç kimse JavaScript’te bland’i DOM’da kullanmıyorsa, günümüzde ham bir veritabanı arayüzüne sahip olmak zorunda değilsiniz.


201
2017-10-12 13:22



Dikkatli olun pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST); işlev - ie: pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true'); - rickyduck
@Tom Sure, her ne kadar çok bakım yapılmasa da (0.9.2 sonuncuydu) fosil hesabıwiki'ye ekle veya dosya a hata raporu (IIRC kaydı olmadan). - mario


mysql_ fonksiyonlar:

  1. güncel değil - artık sürdürülüyor
  2. Başka bir veritabanına kolayca geçmenize izin verme
  3. Hazırlanmış ifadeleri desteklemeyin, dolayısıyla
  4. Programcıları, SQL Injection güvenlik açıklarına yol açan sorgular oluşturmak için birleştirme kullanmaya teşvik etme

136
2018-01-01 17:42



# 2 eşit olarak doğrudur mysqli_ - eggyal
Adil olmak gerekirse, SQL lehçesindeki varyasyonlar göz önünde bulundurulduğunda, PDO bile herhangi bir kesinlik derecesiyle # 2 vermez. Bunun için uygun bir ORM sarıcısına ihtiyacınız var. - SDC
@SDC gerçekten - standartlarla ilgili sorun şu ki yani Bunların birçoğu... - Alnitak
xkcd.com/927 - Lightness Races in Orbit
mysql_* işlev, yeni PHP sürümleri için mysqlnd işlevlerine bir kabuktur. Yani eski istemci kütüphanesi artık korunmasa bile, mysqlnd korunur :) - hakre


Bahsederken teknik nedenleri, sadece birkaç, son derece spesifik ve nadiren kullanılır. Büyük ihtimalle onları asla hayatında kullanmayacaksın.
Belki de çok bilgisizim, ama onlara hiçbir zaman böyle şeyler kullanma fırsatım olmadı

  • engelleme olmayan, eşzamansız sorgular
  • Birden çok sonuç kümesine dönen saklı yordamlar
  • Şifreleme (SSL)
  • Sıkıştırma

Bunlara ihtiyacınız varsa - bunlar, mysql uzantısından daha şık ve modern görünümlü bir şeye doğru gitmek için teknik nedenlerden kuşkusuzdur.

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

  • Bu işlevlerin modern PHP sürümleriyle daha fazla kullanılması, kullanımdan kaldırılmış düzeydeki bildirimleri yükseltir. Sadece kapatılabilirler.
  • uzak bir gelecekte, muhtemelen varsayılan PHP yapısından kaldırılabilirler. Büyük bir anlaşma değil, mydsql ext PECL'ye taşınacak ve her ev sahibi, on yıllardır çalıştığı müşterileri kaybetmek istemedikleri için PHP'yi derlemekten mutluluk duyacaktır.
  • Stackoverflow topluluğundan güçlü direnç. Bu dürüst fonksiyonlardan bahsettiğinizde, katı tabular altında olduklarını söylüyorsunuz.
  • ortalama bir PHP kullanıcısı olmak, büyük ihtimalle bu işlevleri kullanma fikriniz hataya açık ve yanlıştır. Sadece size yanlış yolunu öğreten bu çok sayıda ders ve kılavuzdan dolayı. Fonksiyonların kendileri değil - bunu vurgulamak zorundayım - ama onların kullanımı.

Bu ikinci sorun bir sorundur.
Ancak, bence, önerilen çözüm de daha iyi değil.
Bana öyle görünüyor ki çok idealist Tüm bu PHP kullanıcıları, SQL sorgularını bir kerede düzgün bir şekilde nasıl kullanacaklarını öğrenecekleri bir rüya. Büyük ihtimalle mysql_ * 'i mekanik olarak mysqli_ * ile değiştirirler. yaklaşımı aynı bırakarak. Özellikle mysqli hazırladığı ifadeleri inanılmaz acı verici ve zahmetli hale getiriyor.
Bunu kastetmek istemedim yerli hazırlanan ifadeler korumak için yeterli değil SQL enjeksiyonları ve ne de mysqli ne de PDO bir çözüm sunuyor.

Dolayısıyla, bu dürüst uzantı ile 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,

  • Saklı Yordamları desteklemiyor (kullanıyorduk mysql_query("CALL my_proc"); çağlar için)
  • İşlemleri desteklemiyor (yukarıdakiyle aynı)
  • Çoklu İfadeleri desteklemiyor (onlara kim ihtiyaç duyuyor?)
  • Aktif gelişim altında değil (yani ne? sen herhangi pratik bir şekilde?)
  • Bir OO arayüzü eksik (bir tane oluşturmak için birkaç saat meselesi)
  • Hazırlanmış Deyimleri veya Parametreli Sorguları desteklemiyor

Sonuncusu ilginç bir nokta. Mysql ext desteklemese de yerli hazırlanan ifadeler, güvenlik için gerekli değildir. El ile ele alınan 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);

işteHer şey parametreli ve güvenlidir.

Ama tamam, eğer el kitabındaki kırmızı kutuyu beğenmezseniz, bir seçim problemi ortaya çıkar: mysqli veya PDO?

Peki, cevap şu şekilde olurdu:

  • Bir kullanmanın gerekliliğini anlıyorsanız veritabanı soyutlama katmanı ve bir tane oluşturmak için bir API arıyoruz, mysqli Mysql'e özgü birçok özelliği desteklediği için çok iyi bir seçim.
  • PHP milletlerinin büyük çoğunluğu gibi, uygulama kodunda ham API çağrıları kullanıyorsunuz (aslında yanlış uygulama) - PDO tek seçenekBu uzantı sadece API değil, bir yarı-DAL gibi davrandığından, hala eksik ama birçok önemli özellik sunuyor, bunlardan ikisi PDO'yu mysqli'den eleştirel olarak ayırt ediyor:

    • mysqli'nin aksine, PDO yer tutucuları bağlayabilir değere göreoldukça karmaşık kodların birkaç ekranı olmadan dinamik olarak oluşturulmuş sorguları olanaklı kılar.
    • mysqli, yalnızca mysqlnd yüklemelerinde yapabilirken, mysqli'nin aksine, PDO her zaman sorgu sonucunu basit bir alışılmış dizide döndürebilir.

Yani, eğer ortalama bir PHP kullanıcısıysanız ve yerel hazırlanmış ifadeleri kullanırken kendinizi bir ton baş ağrısı kurtarmak istiyorsanız, PDO - tekrar - tek seçenek.
Ancak, PDO bir gümüş mermi de değil ve sıkıntıları var.
Böylece, tüm yaygın tuzaklar ve karmaşık davalar için çözümler yazdım. PDO etiketi wiki

Yine de, uzantıları hakkında konuşan herkes 2 önemli gerçek Mysqli ve PDO hakkında:

  1. Hazır beyan gümüş mermi değil. Hazırlanan ifadeleri kullanarak bağlanamayan dinamik tanımlayıcılar vardır. Sorgulamayı zor bir görev haline getiren bilinmeyen sayıda parametre içeren dinamik sorgular vardır.

  2. Uygulama kodunda mysqli_ * veya PDO işlevleri görünmemelidir.
    Orada olmalı soyutlama katmanı bunlar arasında uygulama kodu, uygulama, kodlama, hata işleme, vb. tüm kirli işleri yapacak, uygulama kodunu DRY yaparak ve temizleyecektir. Özellikle dinamik sorgu oluşturma gibi karmaşık durumlar için.

Yani, sadece PDO veya mysqli'ye geçmek yeterli değildir. Bunlardan biri, kodlarında işlenmemiş API işlevlerini çağırmak yerine bir ORM veya bir sorgu oluşturucu veya herhangi bir veritabanı soyutlama sınıfı kullanmak zorundadır.
Ve tam tersine - uygulama kodunuz ile mysql API arasında bir soyutlama katmanı varsa - hangi motorun kullanıldığı önemli değil. Mysql ext'i kullanımdan kaldırılana kadar kullanabilir ve daha sonra soyutlama sınıfınızı başka bir motora kolayca yeniden yazabilirsiniz. tüm uygulama koduna sahip olmak.

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

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

Bu tek bir satırı karşılaştırın PDO ile ihtiyacınız olacak kod miktarı.
İle karşılaştırın çılgın miktarda kod Ham Mysqli'nin hazırladığı ifadelere ihtiyacınız olacak. Hata işleme, profil oluşturma, sorgu günlüğünün zaten yerleşik ve çalışır durumda olduğuna dikkat edin.

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

Her bir alan adının altı ila on kez tekrarlandığında her zamanki PDO ekleriyle karşılaştırın - tüm bu çok sayıda isim sahibi yer tutucu, bağlama ve sorgu tanımları.

Başka bir örnek:

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

Pratik bir durumun üstesinden gelmek için PDO için pek bir örnek bulamıyorsunuz.
Ve çok endişeli ve büyük olasılıkla güvensiz olacak.

Yani, bir kez daha - bu sadece ham sürücünün sizin endişeniz olmalı, fakat soyutlama sınıfı, sadece başlangıç ​​kılavuzunun aptalca örnekleri için değil, gerçek yaşamdaki problemleri çözmek için yararlıdır.


99
2017-10-12 13:23



mysql_* güvenlik açıklarının gelmesini çok kolaylaştırır. PHP çok sayıda acemi kullanıcı tarafından kullanıldığından mysql_* teorik olarak bir aksama olmadan kullanılabilir olsa bile, uygulamada aktif olarak zararlıdır. - Madara Uchiha♦
everything is parameterized and safe - parametreli olabilir, ancak işleviniz kullanılmaz gerçek hazırlanan ifadeler. - uınbɐɥs
Nasıl Not under active development sadece% 0,01 olana kadar mı? Eğer bu stand-fonksiyonu ile bir şey inşa ederseniz, bir yılda mysql versiyonunuzu güncelleyin ve çalışmayan bir sisteme bürünüyorsanız, eminim ki '% 0.01' de çok fazla insan var. şunu söylemek isterdim deprecated ve not under active developmentyakından ilişkilidir. Bunun için "hayır (layık)" bir sebep olduğunu söyleyebiliriz, ama gerçek şu ki, seçenekler arasında bir seçim yapıldığında, no active development neredeyse sadece kadar kötü deprecated Diyecektim ki? - Nanne
@MadaraUchiha: Güvenlik açıklarının gelmesinin nasıl kolay olduğunu açıklayabilir misiniz? Özellikle de aynı savunmasızlıkların PDO veya MySQLi'yi etkilemediği durumlarda ... Çünkü bahsettiğiniz tek bir şeyin farkında değilim. - ircmaxell
@ShaquinTrifonoff: elbette, hazırlanmış ifadeleri kullanmaz. Fakat PDO da yokÇoğu insan MySQLi üzerinden tavsiye eder. Bu yüzden burada bunun önemli bir etkisi olduğundan emin değilim. Yukarıdaki kod (biraz daha fazla ayrıştırma ile), varsayılan olarak bir deyim hazırladığınızda PDO'nun yaptığı şeydir ... - ircmaxell


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

Kullanırken mysql_* fonksiyonları ile kullanıcı tarafından sağlanan parametreleri çalıştırmayı unutmamalısınız. mysql_real_escape_string(). Sadece bir yerde unutursanız veya girdinin sadece bir kısmından kaçarsanız, veritabanınız saldırıya maruz kalabilir.

Hazırlanan ifadeleri kullanma PDO veya mysqli Bu tür programlama hatalarının yapılması daha zor olacak.


88
2017-10-12 13:24



Ne yazık ki, MySQLi_ * 'deki değişken bir parametre sayısını (örneğin bir IN yan tümcesinde denetlenecek değerlerin bir listesini geçirmek istediğinizde) geçmek için yetersiz destek, parametrelerin kullanılmamasını teşvik eder ve aynı birleştirilmiş sorguların kullanımını teşvik eder. MySQL_ * çağrıları savunmasız bırak. - Kickstart
Ancak, bir kez daha, güvensizlik, mysql_ * işlevlerinin içsel bir sorunu değil, yanlış kullanım sorunu. - Agamemnus
@Agamemnus Sorun şu ki, mysql_ * özellikle deneyimsiz programcılar için bu "yanlış kullanım" ın uygulanmasını kolaylaştırıyor. Hazırlanan ifadeleri uygulayan kütüphaneler, bu tür bir hata yapmanın zorlaşmasını sağlar. - Trott


Çünkü (diğer nedenlerden dolayı) girdi verilerinin sterilize edilmesini sağlamak çok daha zordur. Parametrized sorguları kullanırsanız, PDO veya mysqli ile yaptığınız gibi riski tamamen ortadan kaldırabilirsiniz.

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

Eğer bir kişi mysqli'nin PDO'sunu kullanacak olsaydı, kullanıcı ismi sona erecekti. "enhzflep); drop table users".

Görmek bobby-tables.com.


71
2017-09-18 12:28



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 mümkün olmasının tek yolu MySQLi ve mysqli_multi_query() işlevi. Ext / mysql ve uninscaped dizeleri ile mümkün kılan tür enjeksiyon gibi şeyler ' OR '1' = '1 erişilememesi gereken veritabanından veri ayıklamak için. Bazı durumlarda alt sorguların enjekte edilmesi mümkündür, ancak veritabanının bu şekilde değiştirilebilmesi hala mümkün değildir. - DaveRandom