PDO तैयार कथनों से कच्ची SQL क्वेरी स्ट्रिंग प्राप्त करना


130

क्या PDOStatement कॉल करते समय कच्चे SQL स्ट्रिंग को निष्पादित करने का कोई तरीका है :: तैयार स्टेटमेंट पर निष्पादित ()? डिबगिंग उद्देश्यों के लिए यह अत्यंत उपयोगी होगा।



1
एक-पंक्ति फ़ंक्शन pdo- डीबग की जाँच करें ।
सालीक

मुझे मिला सबसे साफ तरीका E_PDOStatement पुस्तकालय है। तुम बस करो $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;। यह PDOStatement वर्ग का विस्तार करके काम करता है , इसलिए PDO एपीआई अनुमति देता है के रूप में सुंदर है।
कॉमफ्रीक

जवाबों:


110

मुझे लगता है कि आप का मतलब है कि आप अंतिम एसक्यूएल क्वेरी चाहते हैं, जिसमें पैरामीटर मान इसमें इंटरपोल किए गए हैं। मैं समझता हूं कि यह डिबगिंग के लिए उपयोगी होगा, लेकिन यह तैयार किए गए बयानों के काम करने का तरीका नहीं है। पैरामीटर क्लाइंट-साइड पर तैयार स्टेटमेंट के साथ संयुक्त नहीं हैं, इसलिए पीडीओ को अपने मापदंडों के साथ संयुक्त क्वेरी स्ट्रिंग तक कभी भी पहुंच नहीं होनी चाहिए।

SQL कथन डेटाबेस सर्वर पर भेजा जाता है जब आप तैयारी करते हैं (), और जब आप निष्पादित करते हैं तो पैरामीटर अलग से भेजे जाते हैं। MySQL का सामान्य क्वेरी लॉग आपके द्वारा निष्पादित () के बाद प्रक्षेपित मानों के साथ अंतिम SQL दिखाता है। नीचे मेरे सामान्य क्वेरी लॉग का एक अंश है। मैंने mysql CLI से प्रश्नों को चलाया, PDO से नहीं, लेकिन सिद्धांत समान है।

081016 16:51:28 2 Query       prepare s1 from 'select * from foo where i = ?'
                2 Prepare     [2] select * from foo where i = ?
081016 16:51:39 2 Query       set @a =1
081016 16:51:47 2 Query       execute s1 using @a
                2 Execute     [2] select * from foo where i = 1

यदि आप PDO विशेषता PDO :: ATTR_EMULATE_PREPARES सेट करते हैं, तो आप जो चाहें प्राप्त कर सकते हैं। इस मोड में, पीडीओ SQL क्वेरी में मापदंडों को प्रक्षेपित करता है और जब आप निष्पादित करते हैं तो पूरी क्वेरी भेजता है ()। यह एक सच्ची तैयार क्वेरी नहीं है। आप निष्पादित () से पहले SQL स्ट्रिंग में चर को प्रक्षेपित करके तैयार प्रश्नों के लाभों को दरकिनार करेंगे।


@Afilina से पुनः टिप्पणी करें:

नहीं, निष्पादन के दौरान पाठीय SQL क्वेरी पैरामीटर के साथ संयुक्त नहीं है । तो आपको दिखाने के लिए पीडीओ के लिए कुछ भी नहीं है।

आंतरिक रूप से, यदि आप PDO :: ATTR_EMULATE_PREPARES का उपयोग करते हैं, तो PDO SQL क्वेरी की एक प्रतिलिपि बनाता है और तैयार करने और निष्पादित करने से पहले इसमें पैरामीटर मान इंटरपोल करता है। लेकिन पीडीओ इस संशोधित SQL क्वेरी को उजागर नहीं करता है।

PDOStatement ऑब्जेक्ट के पास एक प्रॉपर्टी $ क्वेरीस्ट्रिंग है, लेकिन यह केवल PDOStatement के लिए कंस्ट्रक्टर में सेट है, और यह तब अपडेट नहीं किया जाता है जब क्वेरी को मापदंडों से दोबारा लिखा जाता है।

यह पीडीओ के लिए एक उचित सुविधा अनुरोध होगा कि वह उनसे लिखित प्रश्न को उजागर करने के लिए कहे। लेकिन जब तक आप पीडीओ का उपयोग नहीं करते हैं, तब तक आपको "पूर्ण" क्वेरी नहीं दी जाएगी: ATTR_EMULATE_PREPARES।

यही कारण है कि मैं MySQL सर्वर के सामान्य क्वेरी लॉग का उपयोग करने के ऊपर वर्कअराउंड दिखाता हूं, क्योंकि इस मामले में भी पैरामीटर प्लेसहोल्डर्स के साथ एक तैयार क्वेरी को सर्वर पर फिर से लिखा जाता है, जिसमें पैरामीटर मान क्वेरी स्ट्रिंग में बैकफिल्ड होते हैं। लेकिन यह केवल लॉगिंग के दौरान किया जाता है, क्वेरी निष्पादन के दौरान नहीं।


10
और जब PDO :: ATTR_EMULATE_PREPARES TRUE पर सेट हो जाता है तो आपको होल क्वेरी कैसे मिलती है?
यासीन झेलेव जू

2
@ यासेन एलेव: यदि पीडीओ तैयारी का अनुकरण कर रहा है, तो यह क्वेरी को तैयार करने से पहले पैरामीटर मान को क्वेरी में प्रक्षेपित करेगा। इसलिए MySQL पैरामीटर प्लेसहोल्डर के साथ क्वेरी का संस्करण कभी नहीं देखता है। MySQL केवल पूर्ण क्वेरी को लॉग करता है।
बिल कारविन

2
@ बिल: 'पैरामीटर्स क्लाइंट-साइड पर तैयार स्टेटमेंट के साथ संयुक्त नहीं हैं' - प्रतीक्षा करें - लेकिन क्या वे सर्वर साइड पर संयुक्त हैं? या mysql DB में मूल्यों को कैसे सम्मिलित करता है?
स्टेन

1
@afilina, नहीं, आप नहीं कर सकते। ऊपर मेरी व्याख्या देखें।
बिल कार्वेन

3
वाह, एक downvote? कृपया मैसेंजर को शूट न करें। मैं सिर्फ यह बता रहा हूं कि यह कैसे काम करता है।
बिल कारविन

107
/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public static function interpolateQuery($query, $params) {
    $keys = array();

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }
    }

    $query = preg_replace($keys, $params, $query, 1, $count);

    #trigger_error('replaced '.$count.' keys');

    return $query;
}

6
क्यों नहीं बस का उपयोग करें strtr(): तेज, सरल, एक ही परिणाम। strtr($query, $params);
टोनी चिबोकास

इसके लिए क्या उपयोग है?

बस के रूप में अच्छी तरह से बंद करो और मेरे धन्यवाद की पेशकश करना चाहता था, इसके लिए एक पूरी अतिरिक्त कक्षा के बाहर था जिसे मैंने अब इसके पक्ष में हटा दिया है क्योंकि यह छोटा और शानदार है :)। तो उन सभी प्रश्नों को डीबग करने के लिए उपयोगी है, जो प्रत्येक एप्लिकेशन को लॉग इन करके प्रत्येक पृष्ठ पर कर रहा है: D
NaughtySquid

इस फ़ंक्शन को देखा और इसने मुझे बहुत खुश किया, हालाँकि, कुछ मुझे समझ में नहीं आया, आप $keyएक होने stringऔर न होने की जाँच क्यों करते हैं $value? क्या मैं कुछ भूल रहा हूँ? इस कारण से मैं यह पूछता हूं कि इस आउटपुट के कारण दूसरा पैरामीटर स्ट्रिंग के रूप में नहीं देखा जाता है:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
केर्विन स्नेजर्स

1
यह एक अच्छी शुरुआत है, लेकिन यह विफल हो जाता है अगर $ परम के मूल्य में स्वयं एक प्रश्न चिह्न ("?") शामिल हो।
चिकनचिल्ली

32

मैंने WHERE IN (?) जैसे कथनों के लिए सरणियों के आउटपुट को शामिल करने के लिए विधि को संशोधित किया।

अद्यतन: केवल NULL मान के लिए जोड़ा गया चेक और डुप्लिकेट किए गए $ params इसलिए वास्तविक $ param मान संशोधित नहीं हैं।

महान काम bigwebguy और धन्यवाद!

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_string($value))
            $values[$key] = "'" . $value . "'";

        if (is_array($value))
            $values[$key] = "'" . implode("','", $value) . "'";

        if (is_null($value))
            $values[$key] = 'NULL';
    }

    $query = preg_replace($keys, $values, $query);

    return $query;
}

2
मुझे लगता है कि आपको $values = $params;इसके बजाय करना होगा $values = array()
परीक्षण

एक और छोटा टुकड़ा जो यहां छूट गया है वह है तार। उन पर कब्जा करने के लिए, इसे is_arrayचेक के ऊपर if (is_string($value)) $values[$key] = "'" . $value . "'";
रखें

यह केवल प्रीग_रेप्ले में केवल एक बार सीमित बाइंड वैल्यू है। इस लाइन को $values = $params; $values_limit = []; $words_repeated = array_count_values(str_word_count($sql, 1, ':_')); जोड़ने के बाद पहले इसे अंदर करें अगर foreach में है $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);और सबसे पहले foreach में $values_limit = [];foreach पाश का उपयोग करते हैं $ मान फिर से preg_replace के साथisset($values_limit[$key])
vee

उदाहरण के लिए लूप $ मान। if (is_array($values)) { foreach ($values as $key => $val) { if (isset($values_limit[$key])) { $sql = preg_replace(['/:'.$key.'/'], [$val], $sql, $values_limit[$key], $count); } } unset($key, $val); } else { $sql = preg_replace($keys, $values, $sql, 1, $count); }
वी

12

थोड़ी देर शायद लेकिन अब वहाँ है PDOStatement::debugDumpParams

आउटपुट पर सीधे तैयार किए गए स्टेटमेंट में शामिल डंप को डंप करता है। यह उपयोग में SQL क्वेरी, उपयोग किए जाने वाले मापदंडों की संख्या (परमेस), मापदंडों की सूची, उनके नाम के साथ, एक पूर्णांक के रूप में, प्रकार (पैरामैप्टाइप), उनके प्रमुख नाम या स्थिति, और क्वेरी में स्थिति (यदि है) प्रदान करेगा पीडीओ चालक द्वारा समर्थित है, अन्यथा, यह -1 होगा)।

आप आधिकारिक php डॉक्स पर अधिक पा सकते हैं

उदाहरण:

<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindValue(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();

$sth->debugDumpParams();

?>


और बेहतर पठनीयता के लिए:echo '<pre>'; $sth->debugDumpParams(); echo '</pre>';
SandroMarques

10

एक समाधान स्वेच्छा से क्वेरी में एक त्रुटि डालना और त्रुटि संदेश को प्रिंट करना है:

//Connection to the database
$co = new PDO('mysql:dbname=myDB;host=localhost','root','');
//We allow to print the errors whenever there is one
$co->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

//We create our prepared statement
$stmt = $co->prepare("ELECT * FROM Person WHERE age=:age"); //I removed the 'S' of 'SELECT'
$stmt->bindValue(':age','18',PDO::PARAM_STR);
try {
    $stmt->execute();
} catch (PDOException $e) {
    echo $e->getMessage();
}

मानक उत्पादन:

SQLSTATE [४२०००]: सिंटेक्स त्रुटि या पहुंच उल्लंघन: [...] पंक्ति १ में 'व्यक्ति * से व्यक्ति की आयु = १ ELECT' के पास

यह ध्यान रखना महत्वपूर्ण है कि यह केवल क्वेरी के पहले 80 अक्षरों को प्रिंट करता है।


मुझे नहीं पता कि यह क्यों अस्वीकृत किया गया था। यह सरल है और यह काम करता है। यह तेजी से काम करता है। लॉग को चालू करने, लॉग में सही लाइन की खोज करने, फिर लॉग को अक्षम करने, फिर लॉग फ़ाइलों को साफ़ करने की तुलना में बहुत तेज़।
बोजान ह्रनाकास

@BojanHrnkas त्रुटि नमूने की लंबाई बहुत सीमित है। ऐसी सरल क्वेरी के लिए किसी प्लेसहोल्डर को केवल मैन्युअल रूप से एक चर के साथ बदलना आसान है। और यह विधि केवल तभी काम करती है जब आप अनुकरण को सक्षम करते हैं।
आपका कॉमन सेंस

9

माइक द्वारा कोड में थोड़ा और जोड़ा गया - एकल उद्धरण जोड़ने के लिए मानों को चलाएं

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }
    // Walk the array to see if we can add single-quotes to strings
    array_walk($values, create_function('&$v, $k', 'if (!is_numeric($v) && $v!="NULL") $v = "\'".$v."\'";'));

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}

1
बहुत उपयोगी रूप से, मैंने PDOStatement वर्ग के bindParam फ़ंक्शन को ओवरराइड करने और पीडीओ के साथ एक स्ट्रिंग या पूर्णांक मान : PARAMS मानों को मान्य करने के लिए कुछ संशोधन किए ।
सर्जियो फ्लोरेस

हम कहाँ देख सकते हैं?
मावग का कहना है कि मोनिका

8

PDOStatement के पास एक सार्वजनिक संपत्ति $ queryString है। यह वही होना चाहिए जो आप चाहते हैं।

मैंने अभी नोटिस किया है कि PDOStatement में एक अनैजेंटिड विधि debugDumpParams () है जिसे आप भी देखना चाहते हैं।


1
DebugDumpParams कोई दस्तावेज php.net/manual/en/pdostatement.debugdumpparams.php
mloskot

नहीं। $ क्वेरीस्ट्रीम में शामिल परम मानों को नहीं दिखाया गया है।
एंड्रियास

5

आप घिरे चर को पकड़ने और उन्हें बाद में उपयोग के लिए स्टोर करने के लिए PDOStatement वर्ग का विस्तार कर सकते हैं। इसके बाद 2 विधियाँ जोड़ी जा सकती हैं, एक वैरिएबल सैनिटाइज़िंग (डीबगबाइंड वेरीएबल्स) के लिए और दूसरा उन वैरिएबल्स के साथ क्वेरी को प्रिंट करने के लिए (डिबग्यूविक):

class DebugPDOStatement extends \PDOStatement{
  private $bound_variables=array();
  protected $pdo;

  protected function __construct($pdo) {
    $this->pdo = $pdo;
  }

  public function bindValue($parameter, $value, $data_type=\PDO::PARAM_STR){
    $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>$value);
    return parent::bindValue($parameter, $value, $data_type);
  }

  public function bindParam($parameter, &$variable, $data_type=\PDO::PARAM_STR, $length=NULL , $driver_options=NULL){
    $this->bound_variables[$parameter] = (object) array('type'=>$data_type, 'value'=>&$variable);
    return parent::bindParam($parameter, $variable, $data_type, $length, $driver_options);
  }

  public function debugBindedVariables(){
    $vars=array();

    foreach($this->bound_variables as $key=>$val){
      $vars[$key] = $val->value;

      if($vars[$key]===NULL)
        continue;

      switch($val->type){
        case \PDO::PARAM_STR: $type = 'string'; break;
        case \PDO::PARAM_BOOL: $type = 'boolean'; break;
        case \PDO::PARAM_INT: $type = 'integer'; break;
        case \PDO::PARAM_NULL: $type = 'null'; break;
        default: $type = FALSE;
      }

      if($type !== FALSE)
        settype($vars[$key], $type);
    }

    if(is_numeric(key($vars)))
      ksort($vars);

    return $vars;
  }

  public function debugQuery(){
    $queryString = $this->queryString;

    $vars=$this->debugBindedVariables();
    $params_are_numeric=is_numeric(key($vars));

    foreach($vars as $key=>&$var){
      switch(gettype($var)){
        case 'string': $var = "'{$var}'"; break;
        case 'integer': $var = "{$var}"; break;
        case 'boolean': $var = $var ? 'TRUE' : 'FALSE'; break;
        case 'NULL': $var = 'NULL';
        default:
      }
    }

    if($params_are_numeric){
      $queryString = preg_replace_callback( '/\?/', function($match) use( &$vars) { return array_shift($vars); }, $queryString);
    }else{
      $queryString = strtr($queryString, $vars);
    }

    echo $queryString.PHP_EOL;
  }
}


class DebugPDO extends \PDO{
  public function __construct($dsn, $username="", $password="", $driver_options=array()) {
    $driver_options[\PDO::ATTR_STATEMENT_CLASS] = array('DebugPDOStatement', array($this));
    $driver_options[\PDO::ATTR_PERSISTENT] = FALSE;
    parent::__construct($dsn,$username,$password, $driver_options);
  }
}

और फिर आप पर्सपाउज़िंग डिबगिंग के लिए इस विरासत वर्ग का उपयोग कर सकते हैं।

$dbh = new DebugPDO('mysql:host=localhost;dbname=test;','user','pass');

$var='user_test';
$sql=$dbh->prepare("SELECT user FROM users WHERE user = :test");
$sql->bindValue(':test', $var, PDO::PARAM_STR);
$sql->execute();

$sql->debugQuery();
print_r($sql->debugBindedVariables());

जिसके परिणामस्वरूप

उन में से चयन उपयोगकर्ता कहां उपयोगकर्ता = 'user_test'

सरणी ([: परीक्षण] => user_test)


4

मैंने अपनी आवश्यकताओं के लिए इस स्थिति पर शोध करने में अच्छा समय बिताया। यह और कई अन्य एसओ थ्रेड्स ने मुझे बहुत हद तक मदद की, इसलिए मैं जो साझा करना चाहता था, उसे साझा करना चाहता था।

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

मेरा समाधान डिफ़ॉल्ट पीडीओएसटेमेंट ऑब्जेक्ट की कार्यक्षमता को विस्तारित मानों (या संदर्भों) को कैश करने के लिए था, और जब स्टेटमेंट निष्पादित किया जाता है, तो क्वेरी में वापस इंजेक्ट होने पर पैरामीटर को ठीक से बाहर निकलने के लिए पीडीओ ऑब्जेक्ट की कार्यक्षमता का उपयोग करें। स्ट्रिंग। हम तब कथन ऑब्जेक्ट की विधि को निष्पादित करने और उस समय निष्पादित वास्तविक क्वेरी को लॉग करने के लिए टाई कर सकते थे ( या संभव के रूप में कम से कम एक प्रजनन के वफादार के रूप में)

जैसा कि मैंने कहा, हम इस कार्यक्षमता को जोड़ने के लिए पूरे कोड आधार को संशोधित नहीं करना चाहते थे, इसलिए हम PDOStatement ऑब्जेक्ट के डिफ़ॉल्ट bindParam()और bindValue()तरीकों को ओवरराइट करते हैं , बाध्य डेटा के हमारे कैशिंग करते हैं, फिर कॉल करें parent::bindParam()या माता-पिता :: bindValue()। इसने हमारे मौजूदा कोड बेस को सामान्य रूप से कार्य करने की अनुमति दी।

अंत में, जब execute()विधि कहा जाता है, हम अपने प्रक्षेप करते हैं और एक नया संपत्ति के रूप में परिणामी स्ट्रिंग प्रदान E_PDOStatement->fullQuery। इस क्वेरी या, उदाहरण के लिए, एक लॉग फ़ाइल के लिए लिखा देखने पर उत्पादन हो सकता है।

एक्सटेंशन, इंस्टॉलेशन और कॉन्फ़िगरेशन निर्देशों के साथ, जीथब पर उपलब्ध हैं:

https://github.com/noahheck/E_PDOStatement

अस्वीकरण :
जाहिर है, जैसा कि मैंने उल्लेख किया है, मैंने यह विस्तार लिखा है। क्योंकि यह यहाँ कई धागे की मदद से विकसित किया गया था, मैं मामले में यहां मेरे समाधान पोस्ट करने के लिए किसी और को इन धागे भर आता है, मैंने किया था बस के रूप में करना चाहता था।


साझा करने के लिए धन्यवाद। कोई उथल-पुथल नहीं क्योंकि बहुत कम कोड के साथ बहुत लंबा जवाब
T30

1

उल्लिखित $ queryString संपत्ति शायद केवल उनके मानों के साथ बदले गए मापदंडों के बिना, पास की गई क्वेरी को वापस कर देगी। .Net में, मेरे पास क्वेरी क्वेरी का कैच भाग होता है, एक साधारण खोज को उनके मूल्यों के साथ मापदंडों पर प्रतिस्थापित करता है जो आपूर्ति की गई थी ताकि त्रुटि लॉग वास्तविक मान दिखा सके जो क्वेरी के लिए उपयोग किया जा रहा था। आपको पीएचपी में मापदंडों की गणना करने में सक्षम होना चाहिए, और मापदंडों को उनके निर्धारित मूल्य से बदलना चाहिए।


1

आप उपयोग कर सकते हैं sprintf(str_replace('?', '"%s"', $sql), ...$params);

यहाँ एक उदाहरण है:

function mysqli_prepared_query($link, $sql, $types='', $params=array()) {
    echo sprintf(str_replace('?', '"%s"', $sql), ...$params);
    //prepare, bind, execute
}

$link = new mysqli($server, $dbusername, $dbpassword, $database);
$sql = "SELECT firstname, lastname FROM users WHERE userage >= ? AND favecolor = ?";
$types = "is"; //integer and string
$params = array(20, "Brown");

if(!$qry = mysqli_prepared_query($link, $sql, $types, $params)){
    echo "Failed";
} else {
    echo "Success";
}

ध्यान दें कि यह केवल PHP> = 5.6 के लिए काम करता है


0

मुझे पता है कि यह सवाल थोड़ा पुराना है, लेकिन, मैं बहुत समय पहले से इस कोड का उपयोग कर रहा हूं (मैंने @ क्रिस-गो से प्रतिक्रिया का उपयोग किया है), और अब, ये कोड PHP 7.2 के साथ अप्रचलित हैं

मैं इन कोड के एक अद्यतन संस्करण पोस्ट करेंगे (से हैं मुख्य कोड के लिए क्रेडिट @bigwebguy , @mike और @ क्रिस-जाने , उन सभी को इस सवाल का जवाब देता है):

/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }
    // Walk the array to see if we can add single-quotes to strings
    array_walk($values, function(&$v, $k) { if (!is_numeric($v) && $v != "NULL") $v = "\'" . $v . "\'"; });

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}

नोट कोड पर परिवर्तन array_walk () फ़ंक्शन पर हैं, एक अनाम फ़ंक्शन द्वारा create_function की जगह। इस कोड के इन अच्छा टुकड़ा कार्यात्मक और PHP 7.2 (और आशा भविष्य के संस्करणों भी) के साथ संगत बनाने।


-1

कुछ हद तक संबंधित ... यदि आप किसी विशेष चर को पवित्र करने की कोशिश कर रहे हैं तो आप पीडीओ :: बोली का उपयोग कर सकते हैं । उदाहरण के लिए, यदि आप CakePHP जैसे सीमित ढांचे के साथ फंस गए हैं, तो कई आंशिक LIKE शर्तों की खोज करें:

$pdo = $this->getDataSource()->getConnection();
$results = $this->find('all', array(
    'conditions' => array(
        'Model.name LIKE ' . $pdo->quote("%{$keyword1}%"),
        'Model.name LIKE ' . $pdo->quote("%{$keyword2}%"),
    ),
);

-1

जब तक आप "पुनः उपयोग" बाइंड मान का उपयोग नहीं कर रहे हैं, तब तक माइक का जवाब अच्छा है।
उदाहरण के लिए:

SELECT * FROM `an_modules` AS `m` LEFT JOIN `an_module_sites` AS `ms` ON m.module_id = ms.module_id WHERE 1 AND `module_enable` = :module_enable AND `site_id` = :site_id AND (`module_system_name` LIKE :search OR `module_version` LIKE :search)

माइक जवाब केवल पहली जगह ले सकता है: खोज नहीं लेकिन दूसरे।
इसलिए, मैं कई मापदंडों के साथ काम करने के लिए उनके उत्तर को फिर से लिखता हूं जो ठीक से उपयोग किया जा सकता है।

public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;
    $values_limit = [];

    $words_repeated = array_count_values(str_word_count($query, 1, ':_'));

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
            $values_limit[$key] = (isset($words_repeated[':'.$key]) ? intval($words_repeated[':'.$key]) : 1);
        } else {
            $keys[] = '/[?]/';
            $values_limit = [];
        }

        if (is_string($value))
            $values[$key] = "'" . $value . "'";

        if (is_array($value))
            $values[$key] = "'" . implode("','", $value) . "'";

        if (is_null($value))
            $values[$key] = 'NULL';
    }

    if (is_array($values)) {
        foreach ($values as $key => $val) {
            if (isset($values_limit[$key])) {
                $query = preg_replace(['/:'.$key.'/'], [$val], $query, $values_limit[$key], $count);
            } else {
                $query = preg_replace(['/:'.$key.'/'], [$val], $query, 1, $count);
            }
        }
        unset($key, $val);
    } else {
        $query = preg_replace($keys, $values, $query, 1, $count);
    }
    unset($keys, $values, $values_limit, $words_repeated);

    return $query;
}

-1

preg_replace ने मेरे लिए काम नहीं किया और जब बाइंडिंग_ 9 से अधिक था, बाइंडिंग_1 और बाइंडिंग_10 को str_replace (0 को पीछे छोड़ते हुए) के साथ बदल दिया गया था, इसलिए मैंने प्रतिस्थापन को पीछे की ओर कर दिया:

public function interpolateQuery($query, $params) {
$keys = array();
    $length = count($params)-1;
    for ($i = $length; $i >=0; $i--) {
            $query  = str_replace(':binding_'.(string)$i, '\''.$params[$i]['val'].'\'', $query);
           }
        // $query  = str_replace('SQL_CALC_FOUND_ROWS', '', $query, $count);
        return $query;

}

आशा है कि कोई इसे उपयोगी पाता है।


-1

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

/**
 * 
 * @param string $str
 * @return string
 */
public function quote($str) {
    if (!is_array($str)) {
        return $this->pdo->quote($str);
    } else {
        $str = implode(',', array_map(function($v) {
                    return $this->quote($v);
                }, $str));

        if (empty($str)) {
            return 'NULL';
        }

        return $str;
    }
}

/**
 * 
 * @param string $query
 * @param array $params
 * @return string
 * @throws Exception
 */
public function interpolateQuery($query, $params) {
    $ps = preg_split("/'/is", $query);
    $pieces = [];
    $prev = null;
    foreach ($ps as $p) {
        $lastChar = substr($p, strlen($p) - 1);

        if ($lastChar != "\\") {
            if ($prev === null) {
                $pieces[] = $p;
            } else {
                $pieces[] = $prev . "'" . $p;
                $prev = null;
            }
        } else {
            $prev .= ($prev === null ? '' : "'") . $p;
        }
    }

    $arr = [];
    $indexQuestionMark = -1;
    $matches = [];

    for ($i = 0; $i < count($pieces); $i++) {
        if ($i % 2 !== 0) {
            $arr[] = "'" . $pieces[$i] . "'";
        } else {
            $st = '';
            $s = $pieces[$i];
            while (!empty($s)) {
                if (preg_match("/(\?|:[A-Z0-9_\-]+)/is", $s, $matches, PREG_OFFSET_CAPTURE)) {
                    $index = $matches[0][1];
                    $st .= substr($s, 0, $index);
                    $key = $matches[0][0];
                    $s = substr($s, $index + strlen($key));

                    if ($key == '?') {
                        $indexQuestionMark++;
                        if (array_key_exists($indexQuestionMark, $params)) {
                            $st .= $this->quote($params[$indexQuestionMark]);
                        } else {
                            throw new Exception('Wrong params in query at ' . $index);
                        }
                    } else {
                        if (array_key_exists($key, $params)) {
                            $st .= $this->quote($params[$key]);
                        } else {
                            throw new Exception('Wrong params in query with key ' . $key);
                        }
                    }
                } else {
                    $st .= $s;
                    $s = null;
                }
            }
            $arr[] = $st;
        }
    }

    return implode('', $arr);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.