पीडीओ डेटाबेस प्रश्नों को कैसे डीबग करें?


140

पीडीओ में जाने से पहले, मैंने स्ट्रिंग को सुगम बनाकर PHP में SQL क्वेरी बनाई। अगर मुझे डेटाबेस सिंटैक्स त्रुटि मिली, तो मैं बस अंतिम SQL क्वेरी स्ट्रिंग को प्रतिध्वनित कर सकता हूं, इसे डेटाबेस पर स्वयं आज़मा सकता हूं, और जब तक मैंने त्रुटि को ठीक नहीं किया, तब तक इसे फिर से कोड में डाल दें।

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

क्या कोई तरीका है जो पीडीओ द्वारा डेटाबेस में भेजी गई पूरी SQL क्वेरी को कैप्चर करता है और उसे एक फाइल में लॉग करता है?


4
यह है एक फ़ाइल में लॉग इन किया: /var/log/mysql/*। PDO बाउंड पैरामीटर सिंटैक्स त्रुटियों का कारण नहीं बन सकता है, इसलिए आपको केवल तैयार SQL क्वेरी की आवश्यकता है।
Xeoncross

1
stackoverflow.com/questions/210564/… (स्वीकृत उत्तर में नहीं) में कोड देखें । ऐसा नहीं है कि कुछ अपडेट पोस्ट किए गए हैं।
मावग का कहना है कि मोनिका

1
संगीतकार के माध्यम से सरल एक-लाइन: github.com/panique/pdo-debug
सालीक

2
Xeoncross के जवाब से मुझे मदद मिली। यहां एक लेख बताया गया है कि इस सुविधा को कैसे चालू किया जाए। यह बहुत सारे सर्वर इंस्टॉलेशन पर डिफ़ॉल्ट है। pontikis.net/blog/how-and-when-to-enable-mysql-logs
mrbinky3000

2
के साथ कोशिश करेंvar_dump($pdo_instance->debugDumpParams())
डैनियल पेट्रोवलिएव

जवाबों:


99

आप यह कहते हैं:

मैं अंतिम क्वेरी को कभी नहीं देखता क्योंकि यह डेटाबेस में भेजा जाता है

ठीक है, वास्तव में, तैयार बयानों का उपयोग करते समय, " अंतिम प्रश्न " जैसी कोई चीज नहीं होती है :

  • सबसे पहले, एक विवरण डीबी को भेजा जाता है, और वहां तैयार किया जाता है
    • डेटाबेस क्वेरी को पार्स करता है, और इसका आंतरिक प्रतिनिधित्व बनाता है
  • और, जब आप चर को बांधते हैं और कथन को निष्पादित करते हैं, तो केवल चर डेटाबेस में भेजे जाते हैं
    • और डेटाबेस बयान के आंतरिक प्रतिनिधित्व में मूल्यों को "इंजेक्ट करता है"


तो, आपके प्रश्न का उत्तर देने के लिए:

क्या कोई तरीका है जो पीडीओ द्वारा डेटाबेस में भेजी गई पूरी SQL क्वेरी को कैप्चर करता है और उसे एक फाइल में लॉग करता है?

नहीं: जैसा कि कहीं भी " पूर्ण SQL क्वेरी " नहीं है, इसे कैप्चर करने का कोई तरीका नहीं है।


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

इस तरह की स्थितियों में, मैं आमतौर पर क्या करता हूं:

  • प्लेसहोल्डर्स के साथ कथन के अनुरूप एसक्यूएल कोड को प्रतिध्वनित करें
  • और मापदंडों के मूल्यों को प्रदर्शित करने के लिए बस var_dump (या समतुल्य) का उपयोग करें
  • यह आमतौर पर एक संभावित त्रुटि को देखने के लिए पर्याप्त है, भले ही आपके पास कोई "वास्तविक" क्वेरी न हो जिसे आप निष्पादित कर सकते हैं।

यह महान नहीं है, जब यह डीबगिंग की बात आती है - लेकिन यह तैयार किए गए बयानों की कीमत है और वे लाभ लाते हैं।


1
महान व्याख्या - धन्यवाद। जाहिरा तौर पर मेरे पास केवल फजी विचार थे कि यह कैसे काम करता है। मुझे लगता है कि जब बयान तैयार किया जाता है, तो परिणामस्वरूप वस्तु में एक हैश या संख्यात्मक आईडी होती है जिसे प्लग इन करने के लिए मापदंडों के साथ डेटाबेस में वापस भेजा जा सकता है।
नाथन लॉन्ग

आपका स्वागत है :-) ;;; मुझे नहीं पता कि इसे विवरणों में कैसे लागू किया जाता है, लेकिन मुझे लगता है कि यह कुछ ऐसा है - परिणाम बिल्कुल वैसा ही है, वैसे भी ;; तैयार कथनों के साथ यह अच्छी चीजों में से एक है: यदि आपको एक ही क्वेरी को बहुत बार निष्पादित करना है, तो इसे केवल डीबी को भेजा जाएगा और एक बार तैयार किया जाएगा: प्रत्येक निष्पादन के लिए, केवल डेटा भेजा जाएगा।
पास्कल मार्टिन

1
अपडेट: आरोन पैटरसन ने Railsconf 2011 में उल्लेख किया कि उन्होंने रेल्स के लिए अधिक तैयार किए गए बयान जोड़े, लेकिन यह लाभ MySQL की तुलना में PostgreSQL में बहुत अधिक भारी है। उन्होंने कहा कि ऐसा इसलिए है क्योंकि MySQL वास्तव में क्वेरी प्लान तब तक नहीं बनाता है जब तक आप तैयार क्वेरी को निष्पादित नहीं करते हैं।
नाथन लॉन्ग

85

डेटाबेस लॉग में देख रहे हैं

हालांकि पास्कल मार्टिन सही है कि पीडीओ एक बार में डेटाबेस को पूरी क्वेरी नहीं भेजता है, डीबी के लॉगिंग फ़ंक्शन का उपयोग करने के लिए ryeguy के सुझाव ने वास्तव में मुझे पूरी क्वेरी को इकट्ठे और डेटाबेस द्वारा निष्पादित के रूप में देखने की अनुमति दी।

यहां बताया गया है: (ये निर्देश विंडोज मशीन पर MySQL के लिए हैं - आपका माइलेज अलग-अलग हो सकता है)

  • में my.ini, के तहत [mysqld]खंड, एक जोड़ने के logआदेश, जैसेlog="C:\Program Files\MySQL\MySQL Server 5.1\data\mysql.log"
  • MySQL को पुनरारंभ करें।
  • यह उस फाइल में हर क्वेरी को लॉग करना शुरू कर देगा।

वह फ़ाइल जल्दी से बढ़ेगी, इसलिए इसे हटाएं और परीक्षण करते समय लॉगिंग बंद कर दें।


1
बस एक नोट - मुझे my.ini में स्लैश से बचना था। तो, मेरी प्रविष्टि ने लॉग = "C: \\ temp \\ MySQL \\ mysql.log" जैसा कुछ देखा।
जिम

4
यह सेटिंग के आधार पर काम कर सकता है PDO::ATTR_EMULATE_PREPARES। अधिक जानकारी के लिए यह उत्तर देखें: stackoverflow.com/questions/10658865/#answer-10658929
webbiedave

23
मुझे पीडीओ से इस वजह से नफरत है।
सलमान

1
@webbiedave - ओह, वाह! आपका जुड़ा हुआ उत्तर बताता है कि मेरा उत्तर केवल तभी काम करता है जब पीडीओ आशावादी रूप से काम नहीं कर रहा है, बल्कि MySQL के पुराने संस्करण या पुराने ड्राइवर के साथ पीछे की संगतता के लिए पूरी क्वेरी भेज रहा है। दिलचस्प।
नाथन लॉन्ग

13
MySQL 5.5+ में आपको general_logइसके बजाय की आवश्यकता है log। देखें dev.mysql.com/doc/refman/5.5/en/query-log.html
एड्रियन मेकनेल

18

सुनिश्चित करें कि आप इस मोड का उपयोग करके डिबग कर सकते हैं {{ PDO::ATTR_ERRMODE }} बस अपनी क्वेरी से पहले नई लाइन जोड़ें, फिर आप डीबग लाइनें दिखाएंगे।

$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$db->query('SELECT *******');  

->queryहालांकि तैयार किए गए कथनों का उपयोग करते समय आप फोन नहीं करेंगे ?
EoghanM

धन्यवाद, कि मुझे बहुत मदद की! :)
अटूट

17

संभवतः आप क्या करना चाहते हैं , स्टेटमेंट हैंडल पर debugDumpParams () का उपयोग करें । आप किसी भी समय तैयार क्वेरी के मानों को बाध्य करने के बाद चला सकते हैं ( execute()कथन की कोई आवश्यकता नहीं )।

यह आपके लिए तैयार कथन का निर्माण नहीं करता है, लेकिन यह आपके मापदंडों को दिखाएगा।


2
एकमात्र समस्या यह है कि यह डिबग को 'इकोइंग' के बिना आंतरिक रूप से स्टोर करने के बजाय आउटपुट करता है। मैं इसे इस तरह से लॉग नहीं कर सकता।
रिकार्डो मार्टिंस

3
आप आउटपुट को संग्रहीत करने और उसे लॉग इन करने के लिए आउटपुट बफ़रिंग (ob_start () ...) का उपयोग कर सकते हैं।
क्रैनियो

Bugs.php.net/bug.php?id=52384 7.1 में तय किया गया है। आप मान देख सकते हैं :) थोड़ा देर से लेकिन यह php है
Sander Visser

12

एक पुरानी पोस्ट लेकिन शायद कोई इसे उपयोगी पाएगा;

function pdo_sql_debug($sql,$placeholders){
    foreach($placeholders as $k => $v){
        $sql = preg_replace('/:'.$k.'/',"'".$v."'",$sql);
    }
    return $sql;
}

1
एक समान फ़ंक्शन के लिए जो संख्यात्मक मापदंडों को भी संभाल सकता है, मेरा उत्तर देखें (php.net पर एक टिप्पणीकार के लिए धन्यवाद)।
मैट ब्राउन ने

9

यहाँ यह देखने के लिए एक समारोह है कि प्रभावी एसक्यूपी क्या होगा, "मार्क" द्वारा एक टिप्पणी से adpated php.net पर :

function sql_debug($sql_string, array $params = null) {
    if (!empty($params)) {
        $indexed = $params == array_values($params);
        foreach($params as $k=>$v) {
            if (is_object($v)) {
                if ($v instanceof \DateTime) $v = $v->format('Y-m-d H:i:s');
                else continue;
            }
            elseif (is_string($v)) $v="'$v'";
            elseif ($v === null) $v='NULL';
            elseif (is_array($v)) $v = implode(',', $v);

            if ($indexed) {
                $sql_string = preg_replace('/\?/', $v, $sql_string, 1);
            }
            else {
                if ($k[0] != ':') $k = ':'.$k; //add leading colon if it was left out
                $sql_string = str_replace($k,$v,$sql_string);
            }
        }
    }
    return $sql_string;
}

"मार्क" $ k से पहले कोलन का उपयोग क्यों करता है str_replace(":$k" ....? सहयोगी अनुक्रमणिका पहले से ही $ params सरणी में है।
एलन

अच्छा सवाल ... यह इसे समझा सकता है: stackoverflow.com/questions/9778887/… । व्यक्तिगत रूप से मैंने इस फ़ंक्शन का उपयोग Doctrine प्रश्नों को डीबग करने के लिए किया था, और मुझे लगता है कि Doctrine नामांकित मापदंडों के बजाय गिने हुए का उपयोग करता है इसलिए मैंने इस मुद्दे को नोटिस नहीं किया। मैंने फ़ंक्शन को अपडेट किया ताकि यह अब अग्रणी कॉलन के साथ या बिना काम करे।
मैट ब्राउन ने

ध्यान दें, कि यह समाधान के :name_longसाथ बदल देता है :name। कम से कम अगर :nameपहले आता है :name_long। MySQL के तैयार कथन इसे सही ढंग से संभाल सकते हैं, इसलिए इसे भ्रमित न होने दें।
Zim84

8

ग्राहक पक्ष पर पीडीओ प्रश्न तैयार नहीं हैं। पीडीओ बस SQL ​​क्वेरी और मापदंडों को डेटाबेस सर्वर को भेजता है। डेटाबेस क्या (प्रतिस्थापन करता है ?के)। आपके पास दो विकल्प हैं:

  • अपने DB के लॉगिंग फ़ंक्शन का उपयोग करें (लेकिन फिर भी यह आम तौर पर दो अलग-अलग बयानों के रूप में दिखाया जाता है (यानी, "अंतिम नहीं") कम से कम तीर्थयात्रियों के साथ)
  • SQL क्वेरी और पैरामैटर्स को आउटपुट करें और इसे अपने आप से जोड़ दें

मैंने कभी डीबी के लॉग की जांच करने के बारे में नहीं सोचा। मैं MySQL डायरेक्टरी में इधर-उधर घूम रहा हूं और कोई लॉग फाइल नहीं देख रहा हूं, लेकिन शायद लॉगिंग एक ऐसा विकल्प है, जिसे मुझे कहीं और चालू करना होगा।
नाथन लॉन्ग

हां, आपको इसे चालू करना होगा। मैं बारीकियों को नहीं जानता लेकिन डिफ़ॉल्ट रूप से यह हर क्वेरी को लॉग नहीं करता है।
रियुगी

5

चेक एरर लॉग को प्रदर्शित करने में त्रुटि के बारे में लगभग कुछ भी नहीं कहा गया था, लेकिन एक उपयोगी सहायक कार्यक्षमता है:

<?php
/* Provoke an error -- bogus SQL syntax */
$stmt = $dbh->prepare('bogus sql');
if (!$stmt) {
    echo "\PDO::errorInfo():\n";
    print_r($dbh->errorInfo());
}
?>

( स्रोत लिंक )

यह स्पष्ट है कि इस कोड को अपवाद संदेश या किसी अन्य प्रकार की त्रुटि हैंडलिंग के रूप में उपयोग करने के लिए संशोधित किया जा सकता है


2
यह गलत तरीका है। पीडीओ इस कोड को बेकार बनाने के लिए काफी स्मार्ट है। इसे त्रुटियों पर अपवाद फेंकने के लिए कहें। PHP इस सीमित कार्य से बेहतर तरीके से बाकी काम करेगी । इसके अलावा, कृपया , सभी त्रुटियों को सीधे ब्राउज़र में नहीं छापना सीखें। बेहतर तरीके हैं।
आपका कॉमन सेंस

3
यह आधिकारिक दस्तावेज है, और निश्चित रूप से कोई भी उत्पादन में उस त्रुटि को प्रिंट नहीं करने वाला था, फिर से यह आधिकारिक साइट (php.net) से एक उदाहरण है, कोड उदाहरण के नीचे लिंक देखें। और निश्चित रूप से बेहतर के लिए अतिरिक्त params $ db-> setAttribute (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION) का उपयोग पीडीओ तात्कालिकता के भीतर करना है, लेकिन दुर्भाग्य से आप उस कोड तक पहुँच नहीं सकते हैं
Zippp

4

उदाहरण के लिए आपके पास यह pdo स्टेटमेंट है:

$query="insert into tblTest (field1, field2, field3)
values (:val1, :val2, :val3)";
$res=$db->prepare($query);
$res->execute(array(
  ':val1'=>$val1,
  ':val2'=>$val2,
  ':val3'=>$val3,
));

अब आप इस तरह एक सरणी को परिभाषित करके निष्पादित क्वेरी प्राप्त कर सकते हैं:

$assoc=array(
  ':val1'=>$val1,
  ':val2'=>$val2,
  ':val3'=>$val3,
);
$exQuery=str_replace(array_keys($assoc), array_values($assoc), $query);
echo $exQuery;

1
मेरे लिए काम किया। आपके पास दूसरे कोड के नमूने में गलती है: ));होना चाहिए );(केवल एक गोल ब्रैकेट)।
जसोम डॉटनेट

2

इंटरनेट पर खोज करने पर मुझे यह एक स्वीकार्य समाधान के रूप में मिला। पीडीओ के बजाय एक अलग वर्ग का उपयोग किया जाता है और पीडीओ फ़ंक्शन को जादू फ़ंक्शन कॉल के माध्यम से कहा जाता है। मुझे यकीन नहीं है कि यह गंभीर प्रदर्शन समस्याएं पैदा करता है। लेकिन इसका उपयोग तब तक किया जा सकता है जब तक कि एक समझदार लॉगिंग सुविधा को पीडीओ में नहीं जोड़ा जाता है।

तो इस धागे के अनुसार , आप अपने पीडीओ कनेक्शन के लिए एक रैपर लिख सकते हैं जो एक त्रुटि मिलने पर लॉग इन कर सकता है और एक अपवाद फेंक सकता है।

यहाँ सरल उदाहरण है:

class LoggedPDOSTatement extends PDOStatement    {

function execute ($array)    {
    parent::execute ($array);
    $errors = parent::errorInfo();
    if ($errors[0] != '00000'):
        throw new Exception ($errors[2]);
    endif;
  }

}

इसलिए आप PDOStatement के बजाय उस क्लास का उपयोग कर सकते हैं:

$this->db->setAttribute (PDO::ATTR_STATEMENT_CLASS, array ('LoggedPDOStatement', array()));

यहाँ एक उल्लेख पीडीओ डेकोरेटर कार्यान्वयन:

class LoggedPDOStatement    {

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

function execute ($params = null)    {
    $result = $this->stmt->execute ($params); 
    if ($this->stmt->errorCode() != PDO::ERR_NONE):
        $errors = $this->stmt->errorInfo();
        $this->paint ($errors[2]);
    endif;
    return $result;
}

function bindValue ($key, $value)    {
    $this->values[$key] = $value;    
    return $this->stmt->bindValue ($key, $value);
}

function paint ($message = false)    {
    echo '<pre>';
    echo '<table cellpadding="5px">';
    echo '<tr><td colspan="2">Message: ' . $message . '</td></tr>';
    echo '<tr><td colspan="2">Query: ' . $this->stmt->queryString . '</td></tr>';
    if (count ($this->values) > 0):
    foreach ($this->values as $key => $value):
    echo '<tr><th align="left" style="background-color: #ccc;">' . $key . '</th><td>' . $value . '</td></tr>';
    endforeach;
    endif;
    echo '</table>';
    echo '</pre>';
}

function __call ($method, $params)    {
    return call_user_func_array (array ($this->stmt, $method), $params); 
}

}

2

MySQL को WAMP में लॉग इन करने के लिए , आपको my.ini को एडिट करना होगा (जैसे wamp \ bin \ mysql \ mysql5.6.17 \ my.ini के तहत)

और इसमें जोड़ें [mysqld]:

general_log = 1
general_log_file="c:\\tmp\\mysql.log"

1

यहां एक फ़ंक्शन है जिसे मैंने "हल" मापदंडों के साथ एक SQL क्वेरी वापस करने के लिए बनाया है।

function paramToString($query, $parameters) {
    if(!empty($parameters)) {
        foreach($parameters as $key => $value) {
            preg_match('/(\?(?!=))/i', $query, $match, PREG_OFFSET_CAPTURE);
            $query = substr_replace($query, $value, $match[0][1], 1);
        }
    }
    return $query;
    $query = "SELECT email FROM table WHERE id = ? AND username = ?";
    $values = [1, 'Super'];

    echo paramToString($query, $values);

आप इस तरह से निष्पादित करते हैं

$values = array(1, 'SomeUsername');
$smth->execute($values);

यह फ़ंक्शन प्रश्नों में उद्धरण नहीं जोड़ता है, लेकिन मेरे लिए काम करता है।


0

डिबगिंग प्रयोजनों के लिए पीडीओ छूट को पकड़ने के लिए मेरे पास समस्या यह थी कि यह केवल पीडीओ छूट (डु) को पकड़ा, लेकिन सिंटैक्स त्रुटियों को नहीं पकड़ा जो php त्रुटियों के रूप में पंजीकृत थे (मुझे यकीन नहीं है कि यह क्यों है, लेकिन " क्यों "समाधान के लिए अप्रासंगिक है)। मेरी सभी पीडीओ कॉल एक सिंगल टेबल मॉडल क्लास से आती हैं, जिसे मैंने सभी तालिकाओं के साथ अपने सभी इंटरैक्शन के लिए बढ़ाया है ... यह जटिल चीजें जब मैं कोड को डीबग करने की कोशिश कर रहा था, क्योंकि त्रुटि php कोड की लाइन को पंजीकृत करेगी जहां मेरा निष्पादन कॉल था कहा जाता है, लेकिन मुझे यह नहीं बताया कि वास्तव में कॉल कहां से किया गया था। मैंने इस समस्या को हल करने के लिए निम्नलिखित कोड का उपयोग किया:

/**
 * Executes a line of sql with PDO.
 * 
 * @param string $sql
 * @param array $params
 */
class TableModel{
    var $_db; //PDO connection
    var $_query; //PDO query

    function execute($sql, $params) { 
        //we're saving this as a global, so it's available to the error handler
        global $_tm;
        //setting these so they're available to the error handler as well
        $this->_sql = $sql;
        $this->_paramArray = $params;            

        $this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->_query = $this->_db->prepare($sql);

        try {
            //set a custom error handler for pdo to catch any php errors
            set_error_handler('pdoErrorHandler');

            //save the table model object to make it available to the pdoErrorHandler
            $_tm = $this;
            $this->_query->execute($params);

            //now we restore the normal error handler
            restore_error_handler();
        } catch (Exception $ex) {
            pdoErrorHandler();
            return false;
        }            
    }
}

इसलिए, उपरोक्त कोड BOTH PDO अपवादों और php सिंटैक्स त्रुटियों को पकड़ता है और उन्हें उसी तरह व्यवहार करता है। मेरा त्रुटि हैंडलर कुछ इस तरह दिखता है:

function pdoErrorHandler() {
    //get all the stuff that we set in the table model
    global $_tm;
    $sql = $_tm->_sql;
    $params = $_tm->_params;
    $query = $tm->_query;

    $message = 'PDO error: ' . $sql . ' (' . implode(', ', $params) . ") \n";

    //get trace info, so we can know where the sql call originated from
    ob_start();
    debug_backtrace(); //I have a custom method here that parses debug backtrace, but this will work as well
    $trace = ob_get_clean();

    //log the error in a civilized manner
    error_log($message);

    if(admin(){
        //print error to screen based on your environment, logged in credentials, etc.
        print_r($message);
    }
}

अगर किसी के पास टेबल मॉडल को वैश्विक चर के रूप में स्थापित करने की तुलना में मेरी त्रुटि हैंडलर के लिए प्रासंगिक जानकारी प्राप्त करने के बारे में कोई बेहतर विचार है, तो मुझे यह सुनकर और अपने कोड को संपादित करने में खुशी होगी।


0

यह कोड मेरे लिए बहुत अच्छा काम करता है:

echo str_replace(array_keys($data), array_values($data), $query->queryString);

$ डेटा और $ क्वेरी को अपने नामों से बदलना न भूलें


0

मैं पीडीओ को डीबग करने के लिए इस क्लास का उपयोग करता हूं ( Log4PHP के साथ )

<?php

/**
 * Extends PDO and logs all queries that are executed and how long
 * they take, including queries issued via prepared statements
 */
class LoggedPDO extends PDO
{

    public static $log = array();

    public function __construct($dsn, $username = null, $password = null, $options = null)
    {
        parent::__construct($dsn, $username, $password, $options);
    }

    public function query($query)
    {
        $result = parent::query($query);
        return $result;
    }

    /**
     * @return LoggedPDOStatement
     */
    public function prepare($statement, $options = NULL)
    {
        if (!$options) {
            $options = array();
        }
        return new \LoggedPDOStatement(parent::prepare($statement, $options));
    }
}

/**
 * PDOStatement decorator that logs when a PDOStatement is
 * executed, and the time it took to run
 * @see LoggedPDO
 */
class LoggedPDOStatement
{

    /**
     * The PDOStatement we decorate
     */
    private $statement;
    protected $_debugValues = null;

    public function __construct(PDOStatement $statement)
    {
        $this->statement = $statement;
    }

    public function getLogger()
    {
        return \Logger::getLogger('PDO sql');
    }

    /**
     * When execute is called record the time it takes and
     * then log the query
     * @return PDO result set
     */
    public function execute(array $params = array())
    {
        $start = microtime(true);
        if (empty($params)) {
            $result = $this->statement->execute();
        } else {
            foreach ($params as $key => $value) {
                $this->_debugValues[$key] = $value;
            }
            $result = $this->statement->execute($params);
        }

        $this->getLogger()->debug($this->_debugQuery());

        $time = microtime(true) - $start;
        $ar = (int) $this->statement->rowCount();
        $this->getLogger()->debug('Affected rows: ' . $ar . ' Query took: ' . round($time * 1000, 3) . ' ms');
        return $result;
    }

    public function bindValue($parameter, $value, $data_type = false)
    {
        $this->_debugValues[$parameter] = $value;
        return $this->statement->bindValue($parameter, $value, $data_type);
    }

    public function _debugQuery($replaced = true)
    {
        $q = $this->statement->queryString;

        if (!$replaced) {
            return $q;
        }

        return preg_replace_callback('/:([0-9a-z_]+)/i', array($this, '_debugReplace'), $q);
    }

    protected function _debugReplace($m)
    {
        $v = $this->_debugValues[$m[0]];

        if ($v === null) {
            return "NULL";
        }
        if (!is_numeric($v)) {
            $v = str_replace("'", "''", $v);
        }

        return "'" . $v . "'";
    }

    /**
     * Other than execute pass all other calls to the PDOStatement object
     * @param string $function_name
     * @param array $parameters arguments
     */
    public function __call($function_name, $parameters)
    {
        return call_user_func_array(array($this->statement, $function_name), $parameters);
    }
}

0

मैंने यहाँ इसके लिए एक आधुनिक कम्पोज़र-लोडेड प्रोजेक्ट / रिपॉजिटरी बनाई है:

पीडीओ-डिबग

यहां प्रोजेक्ट का GitHub घर ढूंढें , एक ब्लॉग पोस्ट देखें जो इसे यहां समझा रहा है । आपके कंपोजर में जोड़ने के लिए एक पंक्ति। Json, और फिर आप इसे इस तरह से उपयोग कर सकते हैं:

echo debugPDO($sql, $parameters);

$ sql कच्चा SQL कथन है, $ पैरामीटर आपके मापदंडों की एक सरणी है: कुंजी प्लेसहोल्डर नाम (": user_id") या अनाम पैरामीटर ("?") की संख्या है, मान है .. अच्छा, है? मूल्य।

पीछे तर्क: यह स्क्रिप्ट बस मापदंडों को वर्गीकृत करेगी और उन्हें प्रदान किए गए SQL स्ट्रिंग में बदल देगी। आपके उपयोग के मामलों के 99% के लिए सुपर-सरल, लेकिन सुपर-प्रभावी। नोट: यह केवल एक मूल अनुकरण है, वास्तविक पीडीओ डिबगिंग नहीं है (जैसा कि यह संभव नहीं है क्योंकि PHP कच्चे एसक्यूएल और मापदंडों को MySQL सर्वर को अलग करता है) भेजता है।

StackOverflow थ्रेड से bigwebguy और माइक के लिए एक बड़ा धन्यवाद मूल रूप से इस स्क्रिप्ट के पीछे पूरे मुख्य फ़ंक्शन को लिखने के लिए PDO से कच्ची SQL क्वेरी स्ट्रिंग प्राप्त करना । प्रसिद्ध बनें!


0

Ubuntu में PDO mysql डेटाबेस प्रश्नों को कैसे डीबग करें

TL; DR अपने सभी प्रश्नों को लॉग करें और mysql लॉग को पूंछें।

ये निर्देश उबंटू के मेरे इंस्टॉल 14.04 के लिए हैं। lsb_release -aअपना संस्करण प्राप्त करने के लिए आदेश जारी करें। आपका इंस्टॉलेशन अलग हो सकता है।

Mysql में लॉगिंग चालू करें

  1. अपने देव सर्वर cmd लाइन पर जाएं
  2. निर्देशिका बदलें cd /etc/mysql। आपको एक फ़ाइल देखनी चाहिए जिसे कहा जाता है my.cnf। यही वह फाइल है जिसे हम बदलने वाले हैं।
  3. यह सत्यापित करें कि आप टाइप करके सही जगह पर हैं cat my.cnf | grep general_log। यह my.cnfआपके लिए फ़ाइल को फ़िल्टर करता है । आपको दो प्रविष्टियाँ #general_log_file = /var/log/mysql/mysql.logदेखनी चाहिए: && #general_log = 1
  4. उन दो पंक्तियों को रद्द करें और अपनी पसंद के संपादक के माध्यम से सहेजें।
  5. Mysql को पुनरारंभ करें sudo service mysql restart:।
  6. आपको अपने वेबसर्वर को भी पुनरारंभ करना पड़ सकता है। (मैं इस्तेमाल किया अनुक्रम याद नहीं कर सकते)। मेरे स्थापित करने के लिए, कि nginx है sudo service nginx restart:।

अच्छा काम! तम तैयार हो। अब आपको बस इतना करना है कि लॉग फाइल को टेल करें ताकि आप देख सकें कि पीडीओ क्वेश्चन आपके ऐप वास्तविक समय में बनाता है।

अपने प्रश्नों को देखने के लिए लॉग इन करें

इस cmd को दर्ज करें tail -f /var/log/mysql/mysql.log

आपका आउटपुट कुछ इस तरह दिखेगा:

73 Connect  xyz@localhost on your_db
73 Query    SET NAMES utf8mb4
74 Connect  xyz@localhost on your_db
75 Connect  xyz@localhost on your_db
74 Quit 
75 Prepare  SELECT email FROM customer WHERE email=? LIMIT ?
75 Execute  SELECT email FROM customer WHERE email='a@b.co' LIMIT 5
75 Close stmt   
75 Quit 
73 Quit 

आपके द्वारा किया गया कोई भी नया प्रश्न स्वचालित रूप से दृश्य में पॉप हो जाएगा , जब तक आप लॉग को जारी रखना जारी रखते हैं। पूंछ से बाहर निकलने के लिए, मारो cmd/ctrl c

टिप्पणियाँ

  1. सावधान: यह लॉग फ़ाइल बहुत बड़ी हो सकती है। मैं केवल अपने देव सर्वर पर इसे चला रहा हूं।
  2. लॉग फ़ाइल बहुत बड़ी हो रही है? इसे काट दो। इसका मतलब है कि फ़ाइल रुकती है, लेकिन सामग्री हटा दी जाती है। truncate --size 0 mysql.log
  3. कूल करें कि लॉग फ़ाइल mysql कनेक्शन को सूचीबद्ध करती है। मुझे पता है कि उनमें से एक मेरी विरासत mysqli कोड से है जिससे मैं संक्रमण कर रहा हूं। तीसरा मेरे नए पीडीओ कनेक्शन से है। हालांकि, निश्चित नहीं है कि दूसरा कहां से आ रहा है। यदि आप इसे खोजने का एक त्वरित तरीका जानते हैं, तो मुझे बताएं।

श्रेय और धन्यवाद

विशाल ने नाथन लॉन्ग के जवाब के लिए ऊपर से इंस्पेक्शन के लिए उबुंटू पर यह पता लगाने के लिए चिल्लाया। साथ ही नाथन की पोस्ट पर उनकी टिप्पणी के लिए डिक्रिल किया जो मुझे इस समाधान तक ले गए।

लव यू ढेरो!


0

डेबियन एनजीआईएनएक्स पर्यावरण में मैंने निम्नलिखित कार्य किया।

गोटो /etc/mysql/mysql.conf.dसंपादित करें mysqld.cnfयदि आप log-error = /var/log/mysql/error.logनिम्न 2 पंक्तियों को जोड़ते हैं तो इसे बंद कर दें।

general_log_file        = /var/log/mysql/mysql.log
general_log             = 1

लॉग गोटो देखने के लिए /var/log/mysqlऔर tail -f mysql.log

याद रखें कि इन डिबगिंग के साथ एक बार जब आप प्रोडक्शन एनवायरनमेंट डिलीट करते हैं, तो इन लाइनों को कमेंट mysql.logकरें क्योंकि यह लॉग फ़ाइल जल्दी से बढ़ेगी और विशाल हो सकती है।


हर कोई mysql का उपयोग नहीं करता है।
डेडिकेटेड सेमीकॉलन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.