PDO প্রস্তুত বিবৃতি থেকে কাঁচা এসকিউএল কোয়েরি স্ট্রিং প্রাপ্ত করা


130

প্রস্তুত বিবৃতিতে PDOStatement :: execute () কল করার সময় কাঁচা এসকিউএল স্ট্রিং কার্যকর করার কোনও উপায় আছে কি? ডিবাগিংয়ের উদ্দেশ্যে এটি অত্যন্ত কার্যকর হবে।


1
পিএইচপি> = 5.1 এর জন্য, php.net/manual/en/pdostatement.debugdumpparams.php
মওগ মোনিকা


সবচেয়ে পরিষ্কার উপায় আমি খুঁজে পেয়েছি হ'ল E_PDOStatement গ্রন্থাগার। আপনি শুধু না $stmt = $pdo->prepare($query); /* ... */ echo $stmt->fullQuery;। এটি PDOStatement শ্রেণি প্রসারিত করে কাজ করে , অতএব PDO API যতটা মার্জিত তা দেয়।
কমফ্রিচ

উত্তর:


110

আমি ধরে নিলাম আপনার অর্থ হ'ল আপনি চূড়ান্ত এসকিউএল কোয়েরিটি চান, এতে প্যারামিটার মানগুলি অন্তর্নিবিষ্ট হয়। আমি বুঝতে পারি যে এটি ডিবাগ করার জন্য দরকারী হবে, তবে প্রস্তুত বিবৃতিগুলি যেভাবে কাজ করে তা এটি নয়। পরামিতিগুলি ক্লায়েন্ট-সাইডে প্রস্তুত বিবৃতিটির সাথে মিলিত হয় না, সুতরাং পিডিওর কাছে কখনও কখনও তার পরামিতিগুলির সাথে মিলিত ক্যোয়ারী স্ট্রিংয়ের অ্যাক্সেস থাকা উচিত নয়।

আপনি () প্রস্তুত করার সময় এসকিউএল বিবৃতিটি ডাটাবেস সার্ভারে প্রেরণ করা হয় এবং আপনি () সম্পাদন করার সময় প্যারামিটারগুলি পৃথকভাবে প্রেরণ করা হয়। মাইএসকিউএলের সাধারণ কোয়েরি লগটি আপনি () কার্যকর করার পরে অন্তরবিচ্ছিন্ন মানগুলির সাথে চূড়ান্ত এসকিউএল দেখায়। নীচে আমার সাধারণ ক্যোয়ারী লগের একটি অংশ রয়েছে। আমি পিএসও থেকে নয়, মাইএসকিএল সিএলআই থেকে অনুসন্ধানগুলি চালিয়েছি, তবে নীতিটি একই।

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 সেট করে দিলে আপনি যা চান তা পেতে পারেন। এই মোডে, PDO এসকিউএল কোয়েরিতে পরামিতিগুলিকে বিভক্ত করে এবং যখন আপনি কার্যকর করেন তখন পুরো ক্যোয়ারী প্রেরণ করে। এটি সত্য প্রস্তুত কোয়েরি নয়। () সম্পাদন করার পূর্বে আপনি এসকিউএল স্ট্রিংয়ে ভেরিয়েবলগুলি ইন্টারপোল্ট করে প্রস্তুত ক্যোয়ারির সুবিধাগুলি হ্রাস করবেন।


@ আফিলিনার মন্তব্য:

না, পাঠ্য এসকিউএল কোয়েরি কার্যকর করার সময় প্যারামিটারগুলির সাথে মিলিত হয় না । সুতরাং পিডিওর জন্য আপনাকে দেখানোর মতো কিছুই নেই।

অভ্যন্তরীণভাবে, আপনি PDO :: ATTR_EMULATE_PREPARES ব্যবহার করে, পিডিও এসকিউএল কোয়েরির একটি অনুলিপি তৈরি করে এবং কার্যকর করার আগে প্যারামিটার মানগুলিকে ইন্টারপোল্ট করে। তবে পিডিও এই সংশোধিত এসকিউএল কোয়েরিটি প্রকাশ করে না।

PDOStatement অবজেক্টটির একটি বৈশিষ্ট্য রয়েছে $ ক্যোয়ারী স্ট্রিং, তবে এটি কেবল PDOStatement এর জন্য নির্ধারকটিতে সেট করা আছে এবং যখন কোয়েরিটি পরামিতিগুলি দিয়ে আবার লেখা হয় তখন তা আপডেট হয় না।

পিডিওর কাছে তাদের পুনর্লিখিত ক্যোয়ারীটি প্রকাশ করার জন্য অনুরোধ করা যুক্তিসঙ্গত বৈশিষ্ট্যের অনুরোধ হবে। আপনি এমনকি PDO :: ATTR_EMULATE_PREPARES ব্যবহার না করা সত্ত্বেও এটি আপনাকে "সম্পূর্ণ" কোয়েরি দেয় না।

এই কারণেই আমি মাইএসকিউএল সার্ভারের সাধারণ ক্যোয়ারী লগটি ব্যবহার করার উপরে ভিত্তি করে কাজটি দেখাই, কারণ এই ক্ষেত্রে এমনকি প্যারামিটারের স্থানধারকগুলির সাথে একটি প্রস্তুত ক্যোয়ারী সার্ভারে আবারও লেখা হয়, যেখানে প্যারামিটার মানগুলি ক্যোয়ারী স্ট্রিংয়ে ব্যাকফুল হয়। তবে এটি কেবল লগিংয়ের সময় করা হয়, কোয়েরি কার্যকর করার সময় নয়।


10
এবং PDO :: ATTR_EMULATE_PREPARES সত্যে সেট করা থাকলে আপনি কীভাবে গর্তের প্রশ্নটি পাবেন?
ইয়াসেন heেলেভ

2
@ ইয়াসেন ঝেলেভ: পিডিও যদি এমুলেট করে প্রস্তুতি নিচ্ছে, তবে ক্যোয়ারি প্রস্তুত করার আগে এটি প্যারামিটার মানগুলিকে ক্যোয়ারিতে বিভক্ত করবে। সুতরাং মাইএসকিউএল কখনই প্যারামিটার স্থানধারীদের সাথে ক্যোয়ারির সংস্করণ দেখতে পায় না। মাইএসকিউএল শুধুমাত্র সম্পূর্ণ কোয়েরি লগ করে।
বিল কারভিন

2
@ বিল: 'ক্লায়েন্ট-সাইডে প্রস্তুত বিবৃতি দিয়ে প্যারামিটারগুলি একত্রিত হয় না' - অপেক্ষা করুন - তবে কি তারা সার্ভারের সাথে মিলিত হয়? অথবা কীভাবে মাইএসকিএল ডিবিতে মান সন্নিবেশ করে?
স্ট্যান

1
@ আফিলিনা, না, আপনি পারবেন না। উপরে আমার ব্যাখ্যা দেখুন।
বিল কারভিন

3
বাহ, একটি ডাউনটাতে? মেসেঞ্জার গুলি করবেন না দয়া করে। আমি কেবল এটি কীভাবে কাজ করে তা বর্ণনা করছি।
বিল কারভিন

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);
টনি চিবুচাস

এর ব্যবহার কী?

শুধু থামিয়ে দিতে এবং আমার ধন্যবাদও দিতে চেয়েছিলেন, এটির জন্য পুরো অতিরিক্ত ক্লাসের বাইরে ছিল যা আমি এখন এটির পক্ষে ক্ষুদ্র ও উজ্জ্বল :) এর পক্ষে সরিয়ে ফেলেছি :)। সুতরাং অ্যাপ্লিকেশন প্রতিটি পৃষ্ঠায় লগইন করে সমস্ত ক্যোরিয়াকে ডিবাগ করার জন্য জঘন্যভাবে উপকারী: ডি
দুষ্টুস্কুইড

এই ফাংশনটি দেখেছি এবং এটি আমাকে খুব আনন্দিত করেছে, যদিও, এমন কিছু যা আমি বুঝতে পারি না, আপনি কেন এবং না $keyহওয়ার জন্য পরীক্ষা stringকরছেন $value? আমি কিছু অনুপস্থিত করছি? আমি এটি জিজ্ঞাসা করার কারণটি এই আউটপুটটির কারণে, দ্বিতীয় প্যারামিটারটি স্ট্রিং হিসাবে দেখা যায় না:string(115) "INSERT INTO tokens (token_type, token_hash, user_id) VALUES ('resetpassword', hzFs5RLMpKwTeShTjP9AkTA2jtxXls86, 1);"
কেরউইন স্নিজডার্স

1
এটি একটি ভাল শুরু, তবে $ পরমের মানটিতে যদি একটি প্রশ্ন চিহ্ন ("?") অন্তর্ভুক্ত থাকে তবে এটি ব্যর্থ হয়।
চিকেনচিলি

32

WHEE IN (?) এর মতো বিবৃতিগুলির জন্য অ্যারেগুলির হ্যান্ডলিং আউটপুট অন্তর্ভুক্ত করার জন্য আমি পদ্ধতিটি পরিবর্তন করেছি।

আপডেট: সবেমাত্র নুল মান এবং ডুপ্লিকেটেড $ প্যারামগুলির জন্য চেক যুক্ত করা হয়েছে যাতে প্রকৃত $ পরম মানগুলি সংশোধিত হয় না।

দুর্দান্ত কাজ 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_arrayif (is_string($value)) $values[$key] = "'" . $value . "'";
এগুলিকে

এটি কেবলমাত্র পূর্ববর্তী স্থানটিতে একবারের জন্য সীমাবদ্ধ মান মান 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])
ভি

উদাহরণস্বরূপ লুপ $ মানগুলি। 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

একটি প্রস্তুত বিবৃতি দ্বারা অন্তর্ভুক্ত তথ্য সরাসরি আউটপুট ডাম্প। এটি ব্যবহৃত এসকিউএল কোয়েরি, ব্যবহৃত প্যারামিটারগুলির সংখ্যা (প্যারাম), তাদের নাম, টাইপ (প্যারামটাইপ) হিসাবে পূর্ণসংখ্যা হিসাবে, তাদের মূল নাম বা অবস্থান এবং কোয়েরিতে অবস্থান সরবরাহ করবে (যদি এটি থাকে) PDO ড্রাইভার দ্বারা সমর্থিত, অন্যথায়, এটি -1 হবে)।

আপনি অফিসিয়াল পিএইচপি ডক্সে আরও খুঁজে পেতে পারেন

উদাহরণ:

<?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>';
স্যান্ড্রোমার্কস

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

স্ট্যান্ডার্ড আউটপুট:

এসকিউএলস্টেট [৪২০০০]: সিনট্যাক্স ত্রুটি বা অ্যাক্সেস লঙ্ঘন: [...] লাইন 1 এ 'ব্যক্তি নির্বাচন করুন থেকে বয়স = 18' এর নিকটে

এটি লক্ষ করা গুরুত্বপূর্ণ যে এটি ক্যোয়ারির প্রথম 80 টি অক্ষর মুদ্রণ করে।


আমি কেন জানি এটিকে নিম্নমানের করা হয়েছিল। এটি সহজ এবং এটি কাজ করে। এটি দ্রুত কাজ করে। লগটি চালু করার চেয়ে খুব দ্রুত, লগটিতে সঠিক লাইনটি অনুসন্ধান করা, তারপরে লগ অক্ষম করা, তারপরে লগ ফাইলগুলি পরিষ্কার করা।
বোজন হর্ণকাস

@ বোজনহ্রনকাস ত্রুটির নমুনার দৈর্ঘ্য অত্যন্ত সীমাবদ্ধ। এ জাতীয় সাধারণ ক্যোয়ারির জন্য প্লেসহোল্ডারকে কেবলমাত্র একটি ভেরিয়েবলের সাথে প্রতিস্থাপন করা সহজ। এবং এই পদ্ধতিটি কেবল তখনই কাজ করে যদি আপনি অনুকরণটি সক্ষম করেন।
আপনার কমন সেন্স

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 শ্রেণীর বাইন্ডপ্রাম ফাংশনটিকে ওভাররাইড করার জন্য কিছু পরিবর্তন করেছি এবং মান পিডিও: পারামস মানগুলির সাথে একটি স্ট্রিং বা পূর্ণসংখ্যা হলে যাচাই করতে পারি
সার্জিও ফ্লোরস

আমরা এটা কোথায় দেখতে পারি?
মাওগ বলছে মনিকা

8

PDOStatement এর একটি সর্বজনীন সম্পত্তি property ক্যোয়ারী স্ট্রিং। আপনি যা চান তা হওয়া উচিত।

আমি কেবল লক্ষ্য করেছি যে PDOStatement এ একটি অননুমোদিত পদ্ধতি ডিবাগডাম্পপ্যারামস () রয়েছে যা আপনি দেখতেও চাইতে পারেন।


1
ডিবাগডাম্পরামগুলি কোনও ডকুমেন্টেড নয় 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());

ফলাফল

ব্যবহারকারীদের কাছ থেকে ব্যবহারকারী নির্বাচন করুন যেখানে ব্যবহারকারী = 'ব্যবহারকারীর তালিকা'

অ্যারে ([: পরীক্ষা] => ব্যবহারকারী_তম)


4

আমি নিজের প্রয়োজনের জন্য এই পরিস্থিতিটি নিয়ে গবেষণা করতে বেশ ভাল সময় ব্যয় করেছি। এটি এবং অন্যান্য বেশ কয়েকটি এসও থ্রেড আমাকে দারুণভাবে সহায়তা করেছিল, তাই আমি কী নিয়ে এসেছি তা ভাগ করে নিতে চাই।

সমস্যা সমাধানের সময় আন্তঃবিবাহিত ক্যোয়ারী স্ট্রিংটিতে অ্যাক্সেস থাকা একটি উল্লেখযোগ্য উপকারিতা থাকা সত্ত্বেও আমরা কেবলমাত্র কিছু নির্দিষ্ট অনুসন্ধানের লগ বজায় রাখতে সক্ষম হতে চাই (অতএব, এই উদ্দেশ্যে ডাটাবেস লগগুলি ব্যবহার করা আদর্শ ছিল না)। আমরা কোনও নির্দিষ্ট সময়ে টেবিলগুলির শর্তটি পুনরায় তৈরি করতে লগগুলি ব্যবহার করতে সক্ষম হতে চেয়েছিলাম, অতএব, আমাদের নিশ্চিত করতে হবে যে অন্তরবিচ্ছিন্ন স্ট্রিংগুলি যথাযথভাবে পালানো হয়েছিল। অবশেষে, আমরা এই কার্যকারিতাটি আমাদের সম্পূর্ণ কোড বেসে যতটা সম্ভব লিখে ফেলতে চাই: (সময়সীমা, বিপণন এবং এগুলি; আপনি এটি কীভাবে জানেন) extend

আমার সমাধানটি ছিল প্যারামিটারাইজড মানগুলি (বা রেফারেন্স) ক্যাশে ডিফল্ট PDOStatement অবজেক্টের কার্যকারিতা বাড়িয়ে দেওয়া, এবং যখন বিবৃতিটি কার্যকর করা হয়, তখন পিআরও অবজেক্টের কার্যকারিতাটি প্যারামিটারগুলিতে যথাযথভাবে পালাতে ব্যবহৃত হয় যখন সেগুলি আবার জিজ্ঞাসায় ইনজেকশন দেওয়া হয় escape স্ট্রিং। তারপরে আমরা স্টেটমেন্ট অবজেক্টের পদ্ধতিটি কার্যকর করতে এবং সেই সময় সম্পাদিত প্রকৃত ক্যোয়ারি লগ করতে পারি ( বা কমপক্ষে যতটা সম্ভব একটি পুনরুত্পদের বিশ্বস্ত)

যেমনটি আমি বলেছি, আমরা এই কার্যকারিতা যুক্ত করার জন্য পুরো কোড বেসটি সংশোধন করতে চাইনি, সুতরাং আমরা পিডিওসেটেটমেন্ট অবজেক্টের ডিফল্ট bindParam()এবং bindValue()পদ্ধতিগুলি ওভাররাইট করি , বাউন্ড ডেটাতে আমাদের ক্যাশে করি, তারপরে কল করুন parent::bindParam()বা প্যারেন্ট করুন :: bindValue()। এটি আমাদের বিদ্যমান কোড বেসকে স্বাভাবিক হিসাবে কাজ করতে দেয়।

শেষ অবধি, যখন execute()পদ্ধতিটি বলা হয়, আমরা আমাদের অন্তরঙ্গকরণ সম্পাদন করি এবং ফলস্বরূপ স্ট্রিংটিকে একটি নতুন সম্পত্তি হিসাবে সরবরাহ করি E_PDOStatement->fullQuery। এটি কোয়েরিটি দেখার জন্য আউটপুট হতে পারে বা উদাহরণস্বরূপ, লগ ফাইলে লেখা।

ইনস্টলেশন এবং কনফিগারেশন নির্দেশাবলী সহ এক্সটেনশনটি গিথুবে উপলভ্য:

https://github.com/noahheck/E_PDOStatement

অস্বীকৃতি :
অবশ্যই, যেমনটি আমি উল্লেখ করেছি, আমি এই এক্সটেনশনটি লিখেছি। যেহেতু এটি এখানে অনেক থ্রেডের সহায়তায় বিকাশ করা হয়েছিল, আমি অন্য যেভাবে এই থ্রেডগুলি জুড়ে আসে সে ক্ষেত্রে আমি এখানে আমার সমাধান পোস্ট করতে চেয়েছিলাম।


ভাগ করে নেওয়ার জন্য ধন্যবাদ. কোনও আপভোট নেই কারণ খুব অল্প কোড সহ খুব দীর্ঘ উত্তর
T30

1

উল্লিখিত $ কোয়েরিস্ট্রিং সম্পত্তি সম্ভবত তাদের মানগুলি পরিবর্তিত প্যারামিটার ব্যতীত কেবল পাস করা ক্যোয়ারীই ফিরিয়ে দেবে। নেট। এ, আমার কাছে আমার ক্যোয়ারী এক্সিকিউটারের ধরা পড়ার অংশটি তাদের মানগুলি সরবরাহ করে যা তাদের মানগুলির সাথে একটি সাধারণ অনুসন্ধান প্রতিস্থাপন করে যাতে ত্রুটি লগটি ক্যোয়ারির জন্য ব্যবহৃত প্রকৃত মানগুলি দেখাতে পারে। আপনার পিএইচপি-তে পরামিতিগুলি গণনা করতে এবং প্যারামিটারগুলি তাদের নির্ধারিত মানের সাথে প্রতিস্থাপন করতে সক্ষম হওয়া উচিত।


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

নোট করুন এটি কেবল পিএইচপি> = 5.6 এর জন্য কাজ করে


0

আমি জানি এই প্রশ্নটি কিছুটা পুরানো, তবে, আমি অনেক আগে থেকেই এই কোডটি ব্যবহার করছি (আমি @ ক্রিস-গো-এর প্রতিক্রিয়া ব্যবহার করেছি), এবং এখন, এই কোডগুলি পিএইচপি 7.2 সহ অপ্রচলিত

আমি এই কোডগুলির একটি আপডেট সংস্করণ পোস্ট করব (মূল কোডটির জন্য ক্রেডিট @ বিগওয়েবগুই , @ মিমিক এবং @ ক্রিস-গো থেকে প্রাপ্ত , এই সমস্ত প্রশ্নের উত্তর):

/**
 * 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;
}

নোটের কোনও ক্রিয়াকলাপের মাধ্যমে create_function প্রতিস্থাপন করে কোডটিতে পরিবর্তনটি অ্যারে_ওয়াক () ফাংশনে রয়েছে Note এটি কোডের এই ভাল টুকরোটিকে পিএইচপি 7.2 (এবং ভবিষ্যতের সংস্করণগুলি আশা করি) সাথে সামঞ্জস্যপূর্ণ করে তুলবে।


-1

কিছুটা সম্পর্কিত ... যদি আপনি কেবল একটি নির্দিষ্ট পরিবর্তনশীল স্যানিটাইজ করার চেষ্টা করছেন আপনি PDO :: উদ্ধৃতি ব্যবহার করতে পারেন । উদাহরণস্বরূপ, আপনি যদি কেকপিএইচপির মতো সীমাবদ্ধ কাঠামোর সাথে আটকে থাকেন তবে একাধিক আংশিক লাইক শর্তগুলির সন্ধান করতে:

$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

প্রিগ_রেপস আমার পক্ষে কাজ করে না এবং যখন বাইন্ডিং_ 9 এর বেশি হয়, বাইন্ডিং_1 এবং বাইন্ডিং_10 টিআর_রেপ্লেস (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);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.