Php güvenli mysql hazırlanmış deyimi oluşturmak nasıl?

6 Cevap php

Ben php ile mysql hazırlanmış deyimleri kullanarak yeni duyuyorum. Ben sütunları almak için hazırlanmış deyimi oluştururken bazı yardıma ihtiyacım var.

Ben farklı sütun bilgi almak gerekir. Şu anda bir test dosyası için, ben completely unsecure SQL deyimini kullanın:

$qry = "SELECT * FROM mytable where userid='{$_GET['userid']}' AND category='{$_GET['category']}'ORDER BY id DESC"
$result = mysql_query($qry) or die(mysql_error());

Birisi bana hazırlanır (yukarıdaki gibi) url parametreleri girişini kullanarak bir secure mysql deyimi oluşturmak yardımcı olabilir misiniz?

BONUS: Hazırlayan ifadeleri de hızını artırmak için varsayalım. Ben sadece bir sayfada hazırlanmış bir deyim üç ya da dört kez kullanmak eğer genel hızını artırmak olacak?

6 Cevap

İşte mysqli (object-sözdizimi - Eğer arzu sözdizimi işlev çevirmek oldukça kolay) kullanarak bir örnek:

$db = new mysqli("host","user","pw","database");
$stmt = $db->prepare("SELECT * FROM mytable where userid=? AND category=? ORDER BY id DESC");
$stmt->bind_param('ii', intval($_GET['userid']), intval($_GET['category']));
$stmt->execute();

$stmt->store_result();
$stmt->bind_result($column1, $column2, $column3);

while($stmt->fetch())
{
    echo "col1=$column1, col2=$column2, col3=$column3 \n";
}

$stmt->close();

Ayrıca, burada yerine kullanışlı bir fonksiyon var, bağlamak için tam olarak ne değişkenleri belirlemek zorunda (SELECT * ile kullanım için) ilişkilendirilebilir diziler kapmak için kolay bir yol isterseniz:

function stmt_bind_assoc (&$stmt, &$out) {
    $data = mysqli_stmt_result_metadata($stmt);
    $fields = array();
    $out = array();

    $fields[0] = $stmt;
    $count = 1;

    while($field = mysqli_fetch_field($data)) {
        $fields[$count] = &$out[$field->name];
        $count++;
    }
    call_user_func_array(mysqli_stmt_bind_result, $fields);
}

Kullanmak için, sadece yerine bind_result çağıran çağırmak:

$stmt->store_result();

$resultrow = array();
stmt_bind_assoc($stmt, $resultrow);

while($stmt->fetch())
{
    print_r($resultrow);
}

Bunu yerine bu yazabilirsiniz:

$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";

Ama hazırlanmış ifadeler kullanmak daha iyi PDO gibi, bir genel kütüphane kullanımı

<?php
/* Execute a prepared statement by passing an array of values */
$sth = $dbh->prepare('SELECT * FROM mytable where userid=? and category=? 
                      order by id DESC');
$sth->execute(array($_GET['userid'],$_GET['category']));
//Consider a while and $sth->fetch() to fetch rows one by one
$allRows = $sth->fetchAll(); 
?>

Ya da, kullanan mysqli

<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$category = $_GET['category'];
$userid = $_GET['userid'];

/* create a prepared statement */
if ($stmt = mysqli_prepare($link, 'SELECT col1, col2 FROM mytable where 
                      userid=? and category=? order by id DESC')) {
    /* bind parameters for markers */
    /* Assumes userid is integer and category is string */
    mysqli_stmt_bind_param($stmt, "is", $userid, $category);  
    /* execute query */
    mysqli_stmt_execute($stmt);
    /* bind result variables */
    mysqli_stmt_bind_result($stmt, $col1, $col2);
    /* fetch value */
    mysqli_stmt_fetch($stmt);
    /* Alternative, use a while:
    while (mysqli_stmt_fetch($stmt)) {
        // use $col1 and $col2 
    }
    */
    /* use $col1 and $col2 */
    echo "COL1: $col1 COL2: $col2\n";
    /* close statement */
    mysqli_stmt_close($stmt);
}

/* close connection */
mysqli_close($link);
?>

Birkaç diğer cevaplar katılıyorum:

  • PHP'nin ext/mysql parametreli SQL deyimleri için destek vardır.
  • Sorgu parametreleri, SQL injection konularda karşı korumada daha güvenilir kabul edilir.
  • mysql_real_escape_string() Ayrıca doğru kullanırsanız etkili olabilir, ama bu kod daha ayrıntılı bulunuyor olabilir.
  • Bazı versiyonlarda, uluslararası karakter setleri ince açıklarını bırakarak, düzgün kaçtı olmayan karakterlerin olgu var. Sorgu parametrelerini kullanarak bu olgu önler.

Ayrıca sorgu parametrelerini kullansanız bile parametreler sadece SQL sorguları değişmez değerler gerçekleşecek, çünkü hala, SQL enjeksiyonu konusunda dikkatli olması dikkat etmelisiniz. Dinamik SQL sorguları oluşturmak ve tablo adı, sütun adı, veya SQL sözdizimi, sorgu parametreleri ne de bu durumda mysql_real_escape_string() yardım herhangi bir diğer bölümü için PHP değişkenleri kullanın. Örneğin:

$query = "SELECT * FROM $the_table ORDER BY $some_column";

Ilgili performans:

  • Eğer farklı parametre değerleri ile hazırlanmış bir sorgu, birden çok kez çalıştırdığınızda performans avantajı geliyor. Sen sorgu ayrıştırma ve hazırlama yükü kaçının. Ama ne sıklıkla aynı PHP isteği aynı SQL sorgu birçok kez çalıştırmak gerekiyor?
  • Bu performans yarar yararlanabilirsiniz bile, etkili bir opcode önbelleğe alma veya veri önbelleğe alma kullanarak gibi performans gidermek için yapabileceği birçok diğer şeyler ile karşılaştırıldığında genellikle sadece hafif bir gelişmedir.
  • Hatta bazı durumlar vardır hazırlanmış bir sorgu harms performansı. Aşağıdaki durumda, örneğin, iyileştirici o might bir joker ile başlayan parametre değeri üstlenmek zorundadır çünkü, arama için bir dizin kullanabilirsiniz kabul edemeyiz:

    SELECT * FROM mytable WHERE textfield LIKE ?
    

PHP MySQL (veya bu konuda herhangi bir başka dil) ile güvenlik bir ölçüde tartışılan bir konudur. Burada bazı harika ipuçları almak için birkaç yerlerdir:

Bence iki en önemli öğe:

  • SQL Injection: PHP'nin mysql_real_escape_string() fonksiyonu (veya benzer bir şey) ile sorgu değişkenlerin tüm kaçmak için emin olun.
  • Input Validation: kullanıcının giriş güvenme. Düzgün sterilize nasıl öğretici ve doğrulama sizin girişler için this bakın.

Hazırlanan tablolar düz eski MySQL / PHP arabirimi tarafından desteklenmez. Sen PDO veya mysqli gerekir. Ama sadece tutucuları yerine isterseniz, check this comment php mysql_query kılavuzu sayfasında.

Benim için iyi bir çözüm gibi görünüyor ki - - Ben çok codesense_mysqli sınıfının bir kopyasını indirmeyi tavsiye mysqli kullanmak için gidiyoruz.

Bu tamamladı ve hazırlanmış deyimleri kullanarak sadece eski MySQL / PHP arayüzü üzerinde ekstra bir veya iki satır alır şekilde ham mysqli kullanarak biriken cruft en gizleyen bir temiz küçük bir sınıf