मेरी वर्तमान परियोजना के लिए मैं एक साधारण QueryBuilder वर्ग का निर्माण कर रहा हूँ। mysqli की bindParam() विधि के साथ बाध्यकारी पैरामीटर को छोड़कर सब कुछ ठीक काम करता है और मुझे त्रुटि नहीं मिल रही है।

कोड और प्रक्रिया:

  • अनुरोध हैंडलर मेरे उपयोगकर्ता मॉडल से निम्नलिखित विधि का आह्वान करता है:

    public function getPasshashByUsername($username) {
      $qb = new SelectQuery();
      $qb->select(['passhash'])
         ->from($this->sourceName)
         ->where('nickname', $username);
      $stmt = $qb->build();
      $resultset = $qb->execute($stmt);
      return $resultset->fetch_assoc()['passhash'] ?? null;
    }
    
  • संभावित पैरामीटर वाले भागों के लिए, SelectQuery वर्ग इस तरह काम करता है:

    public function where($col, $val) {
      $this->aQueryParts['where'] = $this->addCondition('WHERE',$col, $val);
      return $this;
    }
    
    private function addCondition($type, $col, $val) {
      $sExpr = $type . ' ';
      $sType = '';
      if ( is_int($val) || is_bool($val) ) {
        $sExpr .= '? = ' . $val;
        $sType .= 'i';
      } elseif ( is_double($val) ) {
        $sExpr .= '? = ' . $val;
        $sType .= 'd';
      } else {
        $sExpr .= '? LIKE \'' . $val . '\'';
        $sType .= 's';
      }
      $this->sTypes .= $sType;
      $this->aParams[] = $col;
      return $sExpr;
    }
    
  • अब बिल्ड () विधि कार्रवाई में आती है, जहां पैरा बाध्य होंगे:

    public function build() {
      if ( isset($this->aQueryParts['from']) ) {
      $sQuery = '';
      foreach ( $this->aQueryParts as $part ) {
        if ( is_string($part) ) {
          if ( !empty($part) ) {
            $sQuery .= $part . ' ';
          }
          continue;
        }
        if ( is_array($part) ) {
          foreach ( $part as $entry ) {
            if ( !empty($entry) ) {
              $sQuery .= $entry . ' ';
            }
          }
        }
      }
      $this->sQuery = $sQuery;
      // Marker 1
      //$this->sQuery = 'SELECT * FROM vwuser WHERE nickname LIKE \'TestUser\'';
      } else {
        Logger::send('You must at least call from() to get a valid query.');
        die();
      }
      $this->con = (new DatabaseAdapter())->connect();
      if ( !$stmt = $this->con->prepare($this->sQuery) ) {
        $msg = 'Error while preparing statement: "' . $this->sQuery . '"';
        Logger::send($msg);
        die();
      }
      // make params by-ref
      $params = [];
      foreach ( $this->aParams as $param ) {
        $params[] = &$param;
      }
      // Start Marker 2 
      if ( !empty($this->sTypes) ) {
        if ( !$stmt->bind_param($this->sTypes, ...$params) ) {
          $msg = 'Failed to bind parameters to Query: "' . $this->sQuery . '"';
          Logger::send($msg);
          die();
        }
      }
      // End Marker 2
      return $stmt;
    }
    

निष्पादन() विधि सामान्य तरीके से केवल mysqli निष्पादित() को लपेटती है। कोई त्रुटि/अपवाद नहीं फेंका गया है, यह बिना किसी मिलान के परिणाम सेट देता है। XDebug के संबंध में, bind_params() को कॉल करते समय ये प्रासंगिक मान हैं:

$this->sQuery = "SELECT passhash FROM vwuser WHERE ? LIKE 'TestUser'";
$this->sParams = "s";
$this->aParams = [ "nickname" ];

अगर मैं "मार्कर 1" के नीचे की पंक्ति में क्वेरी स्ट्रिंग के हार्डकोडेड असाइनमेंट को असम्बद्ध करता हूं और मार्कर 2 (bind_params की कॉल) के ब्लॉक पर टिप्पणी करता हूं, तो सब कुछ ठीक काम करता है, इसलिए ऐसा लगता है कि कनेक्शन ही मान्य है। मैंने php.net पर पढ़ने के बाद "मेक बाय-रेफ" ब्लॉक डाला है कि bind_params को संदर्भों की आवश्यकता है, लेकिन इसने कुछ भी नहीं बदला।

0
stuck1a 25 पद 2021, 13:27
'nickname' का मिलान 'TestUser' से कैसे हो सकता है? ये दोनों पूरी तरह से अलग तार हैं।
 – 
Dharman
25 पद 2021, 13:50
मुझे समझ में नहीं आता कि आप इसे MySQLi के साथ क्यों करते हैं। यह पीडीओ के साथ सिर्फ दो पंक्तियाँ होंगी।
 – 
Dharman
25 पद 2021, 13:53
उपनाम vwuser . में उपनाम है
 – 
stuck1a
25 पद 2021, 13:55
यह 'TestUser' के मान की तुलना vwuser.nickname के वास्तविक मान से करेगा, जैसे मार्कर 1 से कार्यशील क्वेरी में -> "vwuser से पासहैश चुनें जहां उपनाम 'TestUser' जैसा है"
 – 
stuck1a
25 पद 2021, 14:00
ओह ठीक है, मुझे लगता है कि मैंने कुछ भ्रमित किया = डी ब्रेक के लिए समय
 – 
stuck1a
25 पद 2021, 14:03

2 जवाब

सबसे बढ़िया उत्तर

आपको वास्तव में mysqli के बजाय पीडीओ सीखने या कुछ मौजूदा डेटाबेस एक्सेस लाइब्रेरी का उपयोग करने पर विचार करना चाहिए।

आप कॉलम नामों को बाइंड नहीं कर सकते। पूरी बात यह है कि आप डेटा को बांधते हैं। आप इसे दूसरी तरफ कर रहे हैं। मैं addCondition विधि से छुटकारा पाने की सलाह दूंगा क्योंकि इसका वास्तव में कोई मतलब नहीं है और यह आपके कोड में कई बग का कारण होगा। इसके बजाय केवल तर्कों को सीधे bind_param में पास करें और प्रकारों के लिए str_repeat() का उपयोग करें।

यहां बताया गया है कि आप इसे कैसे कर सकते हैं:

public function where($col, $val)
{
    $this->aQueryParts['where'] = 'WHERE '.$col. '=?';
    $this->aParams[] = $val;
    return $this;
}

public function build()
{
    if (isset($this->aQueryParts['from'])) {
        $sQuery = '';
        foreach ($this->aQueryParts as $part) {
            if (is_string($part)) {
                if (!empty($part)) {
                    $sQuery .= $part . ' ';
                }
                continue;
            }
            if (is_array($part)) {
                foreach ($part as $entry) {
                    if (!empty($entry)) {
                        $sQuery .= $entry . ' ';
                    }
                }
            }
        }
        $this->sQuery = $sQuery;
    // Marker 1
    //$this->sQuery = 'SELECT * FROM vwuser WHERE nickname LIKE \'TestUser\'';
    } else {
        Logger::send('You must at least call from() to get a valid query.');
        die();
    }

    $this->con = (new DatabaseAdapter())->connect();
    $stmt = $this->con->prepare($this->sQuery);
    // Start Marker 2
    if ($this->aParams) {
        $stmt->bind_param(str_repeat('s', count($this->aParams)), ...$this->aParams);
    }

    // End Marker 2
    return $stmt;
}

जैसा कि आप देख सकते हैं, मैंने if कथन भी हटा दिए हैं। आपको मैन्युअल रूप से त्रुटियों की जांच करने के बजाय mysqli त्रुटि रिपोर्टिंग को सक्षम करने पर विचार करना चाहिए।

0
Dharman 25 पद 2021, 14:19
आपके सुझाए गए समाधान के लिए धन्यवाद, मैं इसके बारे में सोचूंगा। यदि उपयोगकर्ता डेटाबेसप्रोवाइडर की सेटिंग में मैन्युअल रूप से mysqli_error_reporting को बंद कर देता है तो यह केवल न्यूनतम अपवाद हैंडलिंग है। लेकिन मैं इस संभावना को दूर करने के बारे में सोच रहा हूं क्योंकि ऐसा लगता है कि यह कोई लाभ नहीं देता है
 – 
stuck1a
25 पद 2021, 14:34

यहाँ सही संस्करण है। धन्यवाद @Dharman मुझे संकेत देने के लिए। लाइन में प्रश्नवाचक चिह्न लगाने को लेकर कुछ भ्रम की स्थिति थी:

$sExpr .= '? LIKE \'' . $val . '\'';

जो निश्चित रूप से होना चाहिए:

$sExpr .= $col . ' LIKE ?';

तो addCondition() का सुधार संस्करण है:

  private function addCondition($type, $col, $val) {
    $sExpr = $type . ' ';
    $sType = '';
    if ( is_int($val) || is_bool($val) ) {
      $sExpr .=  $col . ' = ?';
      $sType .= 'i';
    } elseif ( is_double($val) ) {
      $sExpr .=  $col . ' = ?';
      $sType .= 'd';
    } else {
      $sExpr .= $col . ' LIKE ?';
      $sType .= 's';
    }
    $this->sTypes .= $sType;
    $this->aParams[] = $val;
    return $sExpr;
  }
0
stuck1a 25 पद 2021, 14:38