कई प्रश्नों के लिए पीडीओ समर्थन (PDO_MYSQL, PDO_MYSQLND)


102

मुझे पता है कि पीडीओ एक कथन में निष्पादित कई प्रश्नों का समर्थन नहीं करता है। मैं Googleing कर रहा हूं और PDO_MYSQL और PDO_MYSQLND के बारे में बात करने वाले कुछ पोस्ट पाए गए हैं।

PDO_MySQL किसी भी अन्य पारंपरिक MySQL अनुप्रयोगों की तुलना में अधिक खतरनाक अनुप्रयोग है। पारंपरिक MySQL केवल एक ही SQL क्वेरी की अनुमति देता है। PDO_MySQL में ऐसी कोई सीमा नहीं है, लेकिन आपको कई प्रश्नों के साथ इंजेक्शन लगाने का जोखिम है।

से: PDO और Zend फ्रेमवर्क का उपयोग कर SQL इंजेक्शन के खिलाफ सुरक्षा (जून 2010; जूलियन द्वारा)

ऐसा लगता है कि PDO_MYSQL और PDO_MYSQLND कई प्रश्नों के लिए समर्थन प्रदान करते हैं, लेकिन मैं उनके बारे में अधिक जानकारी नहीं पा रहा हूं। क्या इन परियोजनाओं को बंद कर दिया गया था? क्या अब पीडीओ का उपयोग करके कई प्रश्नों को चलाने का कोई तरीका है।


4
SQL लेनदेन का उपयोग करें।
tereško

आप कई प्रश्नों का उपयोग क्यों करना चाहेंगे? उनका लेन-देन नहीं होता है, यह वैसा ही है जैसा आप उन्हें एक के बाद एक निष्पादित करेंगे। IMHO कोई पेशेवरों, केवल विपक्ष। SQLInjection के मामले में आप हमलावर को जो चाहें वह करने की अनुमति देते हैं।
म्लेको

अब यह 2020 है, और पीडीओ इसका समर्थन करता है - नीचे मेरा जवाब तरीका देखें।
एंड्रीस

जवाबों:


141

जैसा कि मुझे पता है, PHP 5.3 में PDO_MYSQLNDप्रतिस्थापित PDO_MYSQL। भ्रामक हिस्सा यह है कि नाम अभी भी है PDO_MYSQL। तो अब NDL MySQL + PDO के लिए डिफ़ॉल्ट ड्राइवर है।

कुल मिलाकर, आपको एक बार में कई प्रश्नों को निष्पादित करने की आवश्यकता है:

  • PHP 5.3+
  • mysqlnd
  • तैयार बयानों का अनुकरण किया। सुनिश्चित करें कि (डिफ़ॉल्ट) पर PDO::ATTR_EMULATE_PREPARESसेट है 1। वैकल्पिक रूप से आप तैयार किए गए कथनों और $pdo->execसीधे उपयोग से बच सकते हैं।

निष्पादन का उपयोग करना

$db = new PDO("mysql:host=localhost;dbname=test", 'root', '');

// works regardless of statements emulation
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);

$sql = "
DELETE FROM car; 
INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
INSERT INTO car(name, type) VALUES ('car2', 'coupe');
";

$db->exec($sql);

बयानों का उपयोग करना

$db = new PDO("mysql:host=localhost;dbname=test", 'root', '');

// works not with the following set to 0. You can comment this line as 1 is default
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);

$sql = "
DELETE FROM car; 
INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
INSERT INTO car(name, type) VALUES ('car2', 'coupe');
";

$stmt = $db->prepare($sql);
$stmt->execute();

एक नोट:

उपयोग किए गए तैयार किए गए कथनों का उपयोग करते समय, सुनिश्चित करें कि आपने DSN में उचित एन्कोडिंग (जो वास्तविक डेटा एन्कोडिंग को दर्शाता है) सेट किया है (5.3.6 के बाद से उपलब्ध)। अन्यथा SQL इंजेक्शन के लिए थोड़ी संभावना हो सकती है यदि कुछ विषम एन्कोडिंग का उपयोग किया जाता है


37
उत्तर में कुछ भी गलत नहीं है। यह बताता है कि कई प्रश्नों को कैसे निष्पादित किया जाए। आपका अनुमान है कि उत्तर त्रुटिपूर्ण है, इस धारणा से आता है कि क्वेरी में उपयोगकर्ता-इनपुट शामिल है। वैध उपयोग के मामले हैं जहाँ एक साथ कई प्रश्नों को भेजने से प्रदर्शन को लाभ मिल सकता है। आप इस प्रश्न के वैकल्पिक उत्तर के रूप में प्रक्रियाओं का उपयोग करने का सुझाव दे सकते हैं, लेकिन यह इस उत्तर को बुरा नहीं बनाता है।
गजस

9
इस उत्तर में कोड खराब है, और कुछ बहुत ही हानिकारक प्रथाओं को बढ़ावा देता है (तैयार बयानों के लिए अनुकरण का उपयोग, जो SQL इंजेक्शन भेद्यता के लिए कोड को खुला बनाते हैं )। इसका प्रयोग न करें।
tereško

17
इस उत्तर के साथ कुछ भी गलत नहीं है, और विशेष रूप से अनुकरण मोड। यह pdo_mysql में डिफ़ॉल्ट रूप से सक्षम है, और यदि कोई समस्या थी, तो पहले से ही हजारों इंजेक्शन होंगे। लेकिन अभी तक किसी के पास नहीं है। तो यह जाता है।
आपका कॉमन सेंस

3
वास्तव में, केवल एक ही जो न केवल भावनाओं को प्रदान करने में कामयाब रहा, बल्कि कुछ तर्क, ircmaxell था। हालाँकि, उनके द्वारा लाई गई लिंक काफी अप्रासंगिक हैं। पहले एक बिल्कुल भी अनुपयुक्त है क्योंकि यह स्पष्ट रूप से कहता है "पीडीओ हमेशा इस बग से प्रतिरक्षा करता है।" जबकि दूसरा एक उचित एन्कोडिंग सेट करके बस सॉल्व होता है। तो, यह एक नोट के लायक है, न कि चेतावनी और कम आकर्षक।
आपका कॉमन सेंस

6
किसी ऐसे व्यक्ति के रूप में बोलना जो एसक्यूएल का उपयोग करता है जो केवल हमारे डेवलपर्स ने लिखा है (यानी एसक्यूएल इंजेक्शन एक मुद्दा नहीं है), इसने मुझे बड़े पैमाने पर मदद की है, और किसी भी टिप्पणी से यह संकेत मिलता है कि यह कोड हानिकारक है। इसके उपयोग के लिए संदर्भ।
ल्यूक

17

इस के साथ आधे दिन के बाद, पता चला कि पीडीओ एक बग था जहां ...

-

//This would run as expected:
$pdo->exec("valid-stmt1; valid-stmt2;");

-

//This would error out, as expected:
$pdo->exec("non-sense; valid-stmt1;");

-

//Here is the bug:
$pdo->exec("valid-stmt1; non-sense; valid-stmt3;");

यह निष्पादित "valid-stmt1;", पर रोक "non-sense;"और एक त्रुटि कभी नहीं फेंकेंगे। नहीं चलेगा "valid-stmt3;", सच लौटाओ और झूठ बोलो कि सब कुछ अच्छा हुआ।

मैं यह उम्मीद करूंगा कि इसमें त्रुटि होगी "non-sense;"लेकिन ऐसा नहीं है।

यहां मुझे यह जानकारी मिली है: अमान्य PDO क्वेरी त्रुटि नहीं देती है

यहाँ बग: https://bugs.php.net/bug.php?id=61613 है


इसलिए, मैंने mysqli के साथ ऐसा करने की कोशिश की और वास्तव में कोई ठोस जवाब नहीं मिला कि यह कैसे काम करता है इसलिए मैंने सोचा कि मैं इसे सिर्फ उन लोगों के लिए यहां छोड़ता हूं जो इसका उपयोग करना चाहते हैं।

try{
    // db connection
    $mysqli = new mysqli("host", "user" , "password", "database");
    if($mysqli->connect_errno){
        throw new Exception("Connection Failed: [".$mysqli->connect_errno. "] : ".$mysqli->connect_error );
        exit();
    }

    // read file.
    // This file has multiple sql statements.
    $file_sql = file_get_contents("filename.sql");

    if($file_sql == "null" || empty($file_sql) || strlen($file_sql) <= 0){
        throw new Exception("File is empty. I wont run it..");
    }

    //run the sql file contents through the mysqli's multi_query function.
    // here is where it gets complicated...
    // if the first query has errors, here is where you get it.
    $sqlFileResult = $mysqli->multi_query($file_sql);
    // this returns false only if there are errros on first sql statement, it doesn't care about the rest of the sql statements.

    $sqlCount = 1;
    if( $sqlFileResult == false ){
        throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], [".$mysqli->errno."]: '".$mysqli->error."' }");
    }

    // so handle the errors on the subsequent statements like this.
    // while I have more results. This will start from the second sql statement. The first statement errors are thrown above on the $mysqli->multi_query("SQL"); line
    while($mysqli->more_results()){
        $sqlCount++;
        // load the next result set into mysqli's active buffer. if this fails the $mysqli->error, $mysqli->errno will have appropriate error info.
        if($mysqli->next_result() == false){
            throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], Error No: [".$mysqli->errno."]: '".$mysqli->error."' }");
        }
    }
}
catch(Exception $e){
    echo $e->getMessage(). " <pre>".$e->getTraceAsString()."</pre>";
}

क्या यह काम करता है यदि आप $pdo->exec("valid-stmt1; non-sense; valid-stmt3;");पिछले दो निष्पादन के बिना ही चलते हैं ? मैं इसे बीच में त्रुटियों को फेंकने के लिए प्राप्त कर सकता हूं , लेकिन सफल निष्पादन के बाद निष्पादित नहीं होने पर
जेफ पकेट

नहीं, यह नहीं है। यह पीडीओ के साथ बग है।
साईं फनिंदर रेड्डी जे

1
मेरा बुरा, उन 3 $pdo->exec("")एक दूसरे से स्वतंत्र हैं। मैंने अब उन्हें यह इंगित करने के लिए विभाजित किया कि समस्या उत्पन्न होने के लिए उन्हें अनुक्रम में नहीं होना चाहिए। वे 3 एक निष्पादन विवरण में कई प्रश्नों को चलाने के 3 कॉन्फ़िगरेशन हैं।
साईं फनिंदर रेड्डी जे

दिलचस्प। क्या आपको मेरे पोस्ट किए गए प्रश्न को देखने का मौका मिला? मुझे आश्चर्य है कि अगर यह आंशिक रूप से पैच किया गया है क्योंकि मुझे त्रुटि मिल सकती है यदि यह केवल execपृष्ठ पर है, लेकिन अगर मैं execउनमें एक से अधिक SQL स्टेटमेंट के साथ एक से अधिक रन करता हूं, तो मैं यहां एक ही बग को पुन: पेश करता हूं। लेकिन अगर यह केवल execपृष्ठ पर है, तो मैं इसे पुन: पेश नहीं कर सकता।
जेफ पकेट

क्या execआपके पेज पर एक से अधिक कथन हैं?
साईं फनिंदर रेड्डी जे

3

एक त्वरित और गंदा दृष्टिकोण:

function exec_sql_from_file($path, PDO $pdo) {
    if (! preg_match_all("/('(\\\\.|.)*?'|[^;])+/s", file_get_contents($path), $m))
        return;

    foreach ($m[0] as $sql) {
        if (strlen(trim($sql)))
            $pdo->exec($sql);
    }
}

उचित एसक्यूएल स्टेटमेंट एंड पॉइंट्स में विभाजन। कोई त्रुटि जाँच, कोई इंजेक्शन सुरक्षा नहीं है। उपयोग करने से पहले अपने उपयोग को समझें। व्यक्तिगत रूप से, मैं इसका उपयोग एकीकरण परीक्षण के लिए कच्ची माइग्रेशन फ़ाइलों को बोने के लिए करता हूं।


1
यह विफल हो जाता है यदि आपकी SQL फ़ाइल में कोई mysql अंतर्निहित कमांड शामिल हैं ... यह संभवतः आपकी PHP मेमोरी सीमा को भी उड़ा देगा, यदि SQL फ़ाइल बड़ी है ... ;यदि आपकी SQL में प्रक्रिया या ट्रिगर परिभाषाएँ हैं, तो विराम पर विभाजन ... बहुत सारे कारण यह अच्छा नहीं है।
बिल कारविन

1

हजारों लोगों की तरह, मैं इस प्रश्न की तलाश कर रहा हूं:
एक साथ कई प्रश्न चला सकते हैं, और यदि कोई एक त्रुटि थी, तो कोई भी नहीं चलाएगा मैं इस पेज पर हर जगह गया था,
लेकिन हालांकि यहां दोस्तों ने अच्छे उत्तर दिए, ये उत्तर अच्छे नहीं थे मेरी समस्या
तो मैंने एक फ़ंक्शन लिखा है जो अच्छी तरह से काम करता है और sql इंजेक्शन के साथ लगभग कोई समस्या नहीं है।
यह उन लोगों के लिए मददगार हो सकता है, जो इसी तरह के सवालों की तलाश में हैं इसलिए मैंने उन्हें यहां इस्तेमाल करने के लिए रखा है

function arrayOfQuerys($arrayQuery)
{
    $mx = true;
    $conn->beginTransaction();
    try {
        foreach ($arrayQuery AS $item) {
            $stmt = $conn->prepare($item["query"]);
            $stmt->execute($item["params"]);
            $result = $stmt->rowCount();
            if($result == 0)
                $mx = false;
         }
         if($mx == true)
             $conn->commit();
         else
             $conn->rollBack();
    } catch (Exception $e) {
        $conn->rollBack();
        echo "Failed: " . $e->getMessage();
    }
    return $mx;
}

उपयोग के लिए (उदाहरण):

 $arrayQuery = Array(
    Array(
        "query" => "UPDATE test SET title = ? WHERE test.id = ?",
        "params" => Array("aa1", 1)
    ),
    Array(
        "query" => "UPDATE test SET title = ? WHERE test.id = ?",
        "params" => Array("bb1", 2)
    )
);
arrayOfQuerys($arrayQuery);

और मेरा कनेक्शन:

    try {
        $options = array(
            //For updates where newvalue = oldvalue PDOStatement::rowCount()   returns zero. You can use this:
            PDO::MYSQL_ATTR_FOUND_ROWS => true
        );
        $conn = new PDO("mysql:host=$servername;dbname=$database", $username, $password, $options);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        echo "Error connecting to SQL Server: " . $e->getMessage();
    }

नोट:
यह समाधान आपको एक साथ कई स्टेटमेंट चलाने में मदद करता है,
यदि कोई गलत स्टेटमेंट होता है, तो वह किसी अन्य स्टेटमेंट को निष्पादित नहीं करता है


0

निम्नलिखित कोड की कोशिश की

 $db = new PDO("mysql:host={$dbhost};dbname={$dbname};charset=utf8", $dbuser, $dbpass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

फिर

 try {
 $db->query('SET NAMES gbk');
 $stmt = $db->prepare('SELECT * FROM 2_1_paidused WHERE NumberRenamed = ? LIMIT 1');
 $stmt->execute(array("\xbf\x27 OR 1=1 /*"));
 }
 catch (PDOException $e){
 echo "DataBase Errorz: " .$e->getMessage() .'<br>';
 }
 catch (Exception $e) {
 echo "General Errorz: ".$e->getMessage() .'<br>';
 }

और मिला

DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '/*' LIMIT 1' at line 1

अगर $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);बाद में जोड़े$db = ...

फिर खाली पृष्ठ मिला

अगर इसके बजाय SELECTकोशिश की गई DELETE, तो दोनों मामलों में त्रुटि हुई

 DataBase Errorz: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '* FROM 2_1_paidused WHERE NumberRenamed = '¿\' OR 1=1 /*' LIMIT 1' at line 1

तो मेरा निष्कर्ष है कि कोई इंजेक्शन संभव नहीं ...


3
आपको इसे एक नया प्रश्न बनाना चाहिए था जहाँ इस का संदर्भ दिया गया था
योर कॉमन सेंस

मैं क्या करने की कोशिश के परिणामस्वरूप इतना सवाल नहीं है। और मेरा निष्कर्ष। प्रारंभिक प्रश्न पुराना है, संभवतः वास्तविक नहीं है।
एंड्रीस

यह निश्चित नहीं है कि यह प्रश्न में किसी भी चीज के लिए कैसे प्रासंगिक है।
cHao

सवाल में हैं शब्द but you risk to be injected with multiple queries.मेरा जवाब इंजेक्शन के बारे में है
एंड्रीस

0

इस फ़ंक्शन को आज़माएँ: mltiple क्वेरीज़ और कई मान सम्मिलन।

function employmentStatus($Status) {
$pdo = PDO2::getInstance();

$sql_parts = array(); 
for($i=0; $i<count($Status); $i++){
    $sql_parts[] = "(:userID, :val$i)";
}

$requete = $pdo->dbh->prepare("DELETE FROM employment_status WHERE userid = :userID; INSERT INTO employment_status (userid, status) VALUES ".implode(",", $sql_parts));
$requete->bindParam(":userID", $_SESSION['userID'],PDO::PARAM_INT);
for($i=0; $i<count($Status); $i++){
    $requete->bindParam(":val$i", $Status[$i],PDO::PARAM_STR);
}
if ($requete->execute()) {
    return true;
}
return $requete->errorInfo();
}

0

पीडीओ इसका समर्थन करता है (2020 तक)। बस एक क्वेरी () एक पीडीओ ऑब्जेक्ट पर हमेशा की तरह, प्रश्नों को अलग करके कॉल करें; और फिर अगला चुनें () अगले चयन परिणाम के लिए कदम, अगर आपके पास कई हैं। परिणाम उसी क्रम में होंगे जैसे प्रश्न। स्पष्ट रूप से सुरक्षा निहितार्थ के बारे में सोचें - इसलिए उपयोगकर्ता द्वारा दिए गए प्रश्नों को स्वीकार न करें, मापदंडों का उपयोग करें, आदि। मैं उदाहरण के लिए कोड द्वारा उत्पन्न प्रश्नों के साथ इसका उपयोग करता हूं।

$statement = $connection->query($query);
do {
  $data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
} while ($statement->nextRowset());

मैं इस तरह के तर्क को कभी नहीं समझ पाऊंगा, "यहां एक कोड है जो सभी अनुशंसित अच्छी प्रथाओं की उपेक्षा करने वाले सुरक्षा में एक बड़ा छेद है, इसलिए आपको सुरक्षा निहितार्थ के बारे में सोचने की आवश्यकता है।" इसके बारे में किसे सोचना चाहिए? जब उन्हें सोचना चाहिए - इस कोड का उपयोग करने से पहले या बाद में उन्हें हैक कर लिया जाए? इस फ़ंक्शन को लिखने या अन्य लोगों को देने से पहले आप इसके बारे में पहले क्यों नहीं सोचते हैं?
आपका कॉमन सेंस

प्रिय @YourCommonSense एक ही बार में कई प्रश्नों को चलाने में प्रदर्शन के साथ मदद करता है, कम नेटवर्क ट्रैफ़िक + सर्वर संबंधित प्रश्नों को अनुकूलित कर सकता है। मेरा (सरलीकृत) उदाहरण केवल इसका उपयोग करने के लिए आवश्यक विधि को पेश करने के लिए था। यदि आप उन अच्छी प्रथाओं का उपयोग नहीं करते हैं, तो यह एकांत छेद है। BTW, मुझे उन लोगों पर संदेह है जो कहते हैं कि "मैं कभी नहीं समझ पाऊंगा ..." जब वे आसानी से कर सकते हैं ... :-)
एंड्रीस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.