दिलचस्प पोस्ट
कैसे textarea पर keypress दर्ज करने के लिए पकड़ लेकिन बदलाव नहीं + दर्ज करें? विंडोज फॉर्म के साथ एमवीसी लागू करना ट्री डेटा संरचना के लिए डेटाबेस संरचना नोड में पासपोर्ट जे एस क्यों लॉगआउट पर सत्र नहीं हटा रहा है एक सेलेरी टास्क में एक स्कैरा मकड़ी चलाएं क्या हमें सूची दृश्य को बदलने के लिए रीसाइक्लाइजर का उपयोग करना चाहिए? पृष्ठ को पूरी तरह से भरी हुई फंक्शन कैसे निष्पादित करें? मैं angular.js में राइट-क्लिक इवेंट कैसे प्रबंधित करूँ? क्या मैं अपने एएसपी.नेट एमवीसी व्यू के लिए एक गुमनाम प्रकार पारित कर सकता हूं? एक जावास्क्रिप्ट फ़ंक्शन को प्रोग्राम में जोड़ना अंतिम डाली गई पंक्ति के एंटनम्बर वैल्यू – एमएस एक्सेस / वीबीए वेब अनुप्रयोग आईओएस उपकरणों को पुश सूचनाएं कैसे भेज सकता है? एक अस्थायी के एक उप वस्तु के लिए एक const संदर्भ बाध्य करने के बारे में मेरा Magento एक्सटेंशन इंस्टॉल स्क्रिप्ट रन नहीं होगा श्रेणी -18 से 127 में पूर्णांक वर्ग कैशिंग मूल्य क्या है?

संदर्भ: MySQL एक्सटेंशन का उपयोग करके एक आदर्श कोड नमूना क्या है?

यह एक समुदाय सीखने संसाधन बनाने के लिए है लक्ष्य को अच्छे कोड के उदाहरण हैं, जो भयानक गलतियों को दोहराने नहीं करते हैं, जिन्हें अक्सर कॉपी / चिपकाया गया PHP कोड में पाया जा सकता है। मैंने अनुरोध किया है कि इसे सामुदायिक विकी बनाया जाए।

यह एक कोडन प्रतियोगिता के रूप में नहीं है। यह एक क्वेरी करने के लिए सबसे तेज़ या सबसे कॉम्पैक्ट तरीके खोजने के बारे में नहीं है – यह एक अच्छा, पठनीय संदर्भ विशेष रूप से नये के लिए प्रदान करना है।

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

mysql_* पुस्तकालय का उपयोग कर कोड के साथ सामान्य समस्याएं शामिल हैं:

  • मूल्यों में एसक्यूएल इंजेक्शन
  • सीएमएल इंजेक्शन सीमेंट सीमाओं और गतिशील तालिका नामों में
  • कोई त्रुटि रिपोर्टिंग नहीं ("यह क्वेरी क्यों काम नहीं करता?")
  • टूटी हुई त्रुटि रिपोर्टिंग (वह यह है कि, त्रुटियां हमेशा तब होती हैं जब कोड को उत्पादन में डाल दिया जाता है)
  • मूल्य आउटपुट में क्रॉस-साइट स्क्रिप्टिंग (एक्सएसएस) इंजेक्शन

चलो एक PHP कोड नमूना लिखते हैं जो निम्न कार्य करता है mySQL_ * फ़ंक्शन का परिवार :

  • दो पोस्ट मान, id (संख्यात्मक) और name (एक स्ट्रिंग) स्वीकार करें
  • आईडी id साथ पंक्ति में name कॉलम को बदलकर तालिका तालिका name पर एक UPDATE क्वेरी करें
  • विफलता पर, अनुग्रह से बाहर निकलें, लेकिन केवल उत्पादन मोड में विस्तृत त्रुटि दिखाएं। trigger_error() पर्याप्त होगा; वैकल्पिक रूप से अपनी पसंद का एक तरीका उपयोग करें
  • आउटपुट संदेश " $name updated।"

और ऊपर सूचीबद्ध किसी भी कमजोरियों को नहीं दिखाता है

यह यथासंभव सरल होना चाहिए। यह आदर्श रूप से किसी भी कार्य या वर्ग शामिल नहीं है। लक्ष्य प्रतिलिपि / पेटेबल लाइब्रेरी बनाने के लिए नहीं है, बल्कि डेटाबेस को सुरक्षित करने के लिए क्वेरी करने के लिए कम से कम क्या करना चाहिए।

अच्छी टिप्पणियों के लिए बोनस अंक

लक्ष्य इस प्रश्न को एक संसाधन बनाने के लिए है, जो एक उपयोगकर्ता एक प्रश्न पूछने वाले के साथ लिंक कर सकता है, जिसमें खराब कोड है (भले ही वह सवाल का फ़ोकस नहीं हो) या असफल प्रश्न के मुकाबले है या नहीं पता कैसे इसे ठीक करने के लिए

पीडीओ चर्चा को पूर्व-इम्प्रेट करने के लिए:

हां, पीडीओ में उन प्रश्नों को लिखने वाले व्यक्तियों को निर्देशित करने के लिए अक्सर यह बेहतर होगा जब यह एक विकल्प होता है, तो हमें ऐसा करना चाहिए। यह, हालांकि, हमेशा संभव नहीं है – कभी-कभी प्रश्न पूछने वाला विरासत कोड पर काम कर रहा है, या पहले से ही इस पुस्तकालय के साथ एक लंबा रास्ता तय किया है, और अब इसे बदलने की संभावना नहीं है। इसके अलावा, mysql_* फ़ंक्शन का परिवार पूरी तरह से सुरक्षित है अगर ठीक से उपयोग किया जाता है। तो नहीं "पीडीओ का उपयोग करें" यहां उत्तर दें

Solutions Collecting From Web of "संदर्भ: MySQL एक्सटेंशन का उपयोग करके एक आदर्श कोड नमूना क्या है?"

उस पर मेरा चाकू इसे यथासंभव सरल रखने की कोशिश की, जबकि अभी भी कुछ वास्तविक दुनिया की सुविधा बनाए रखने के लिए।

यूनिकोड संभालता है और पठनीयता के लिए ढीली तुलना करता है। अच्छा होगा 😉

 <?php header('Content-type: text/html; charset=utf-8'); error_reporting(E_ALL | E_STRICT); ini_set('display_errors', 1); // display_errors can be changed to 0 in production mode to // suppress PHP's error messages /* Can be used for testing $_POST['id'] = 1; $_POST['name'] = 'Markus'; */ $config = array( 'host' => '127.0.0.1', 'user' => 'my_user', 'pass' => 'my_pass', 'db' => 'my_database' ); # Connect and disable mysql error output $connection = @mysql_connect($config['host'], $config['user'], $config['pass']); if (!$connection) { trigger_error('Unable to connect to database: ' . mysql_error(), E_USER_ERROR); } if (!mysql_select_db($config['db'])) { trigger_error('Unable to select db: ' . mysql_error(), E_USER_ERROR); } if (!mysql_set_charset('utf8')) { trigger_error('Unable to set charset for db connection: ' . mysql_error(), E_USER_ERROR); } $result = mysql_query( 'UPDATE tablename SET name = "' . mysql_real_escape_string($_POST['name']) . '" WHERE id = "' . mysql_real_escape_string($_POST['id']) . '"' ); if ($result) { echo htmlentities($_POST['name'], ENT_COMPAT, 'utf-8') . ' updated.'; } else { trigger_error('Unable to update db: ' . mysql_error(), E_USER_ERROR); } 

मैंने बंदूक कूदने का फैसला किया और बस कुछ ऊपर डाल दिया। इसके साथ शुरू करने के लिए कुछ है त्रुटि पर अपवाद फेंकता है

 function executeQuery($query, $args) { $cleaned = array_map('mysql_real_escape_string', $args); if($result = mysql_query(vsprintf($query, $cleaned))) { return $result; } else { throw new Exception('MySQL Query Error: ' . mysql_error()); } } function updateTablenameName($id, $name) { $query = "UPDATE tablename SET name = '%s' WHERE id = %d"; return executeQuery($query, array($name, $id)); } try { updateTablenameName($_POST['id'], $_POST['name']); } catch(Exception $e) { echo $e->getMessage(); exit(); } 
 /** * Rule #0: never trust users input! */ //sanitize integer value $id = intval($_GET['id']); //sanitize string value; $name = mysql_real_escape_string($_POST['name']); //1. using `dbname`. is better than using mysql_select_db() //2. names of tables and columns should be quoted by "`" symbol //3. each variable should be sanitized (even in LIMIT clause) $q = mysql_query("UPDATE `dbname`.`tablename` SET `name`='".$name."' WHERE `id`='".$id."' LIMIT 0,1 "); if ($q===false) { trigger_error('Error in query: '.mysql_error(), E_USER_WARNING); } else { //be careful! $name contains user's data, remember Rule #0 //always use htmlspecialchars() to sanitize user's data in output print htmlspecialchars($name).' updated'; } ######################################################################## //Example, how easily is to use set_error_handler() and trigger_error() //to control error reporting in production and dev-code //Do NOT use error_reporting(0) or error_reporting(~E_ALL) - each error //should be fixed, not muted function err_handler($errno, $errstr, $errfile, $errline) { $hanle_errors_print = E_ALL & ~E_NOTICE; //if we want to print this type of errors (other types we can just write in log-file) if ($errno & $hanle_errors_print) { //$errstr can contain user's data, so... Rule #0 print PHP_EOL.'Error ['.$errno.'] in file '.$errfile.' in line '.$errline .': '.htmlspecialchars($errstr).PHP_EOL; } //here you can write error into log-file } set_error_handler('err_handler', E_ALL & ~E_NOTICE & E_USER_NOTICE & ~E_STRICT & ~E_DEPRECATED); 

और टिप्पणियों के कुछ स्पष्टीकरण:

 //1. using `dbname`. is better than using mysql_select_db() 

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

 //2. names of tables and columns should be quoted by "`" symbol 

कॉलम के कुछ नाम एसक्यूएल-कीवर्ड भी हो सकते हैं, और " ` 'प्रतीक का प्रयोग करके उसमें मदद मिलेगी।
इसके अलावा, सभी स्ट्रिंग-वैल्यू, क्वेरी में डाली गई, ' प्रतीक द्वारा उद्धृत किया जाना चाहिए

//always use htmlspecialchars() to sanitize user's data in output
यह XSS- हमलों को रोकने के लिए आपकी सहायता करेगा

 <? mysql_connect(); mysql_select_db("new"); $table = "test"; if($_SERVER['REQUEST_METHOD']=='POST') { $name = mysql_real_escape_string($_POST['name']); if ($id = intval($_POST['id'])) { $query="UPDATE $table SET name='$name' WHERE id=$id"; } else { $query="INSERT INTO $table SET name='$name'"; } mysql_query($query) or trigger_error(mysql_error()." in ".$query); header("Location: http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']); exit; } if (!isset($_GET['id'])) { $LIST=array(); $query="SELECT * FROM $table"; $res=mysql_query($query); while($row=mysql_fetch_assoc($res)) $LIST[]=$row; include 'list.php'; } else { if ($id=intval($_GET['id'])) { $query="SELECT * FROM $table WHERE id=$id"; $res=mysql_query($query); $row=mysql_fetch_assoc($res); foreach ($row as $k => $v) $row[$k]=htmlspecialchars($v); } else { $row['name']=''; $row['id']=0; } include 'form.php'; } ?> 

form.php

 <? include 'tpl_top.php' ?> <form method="POST"> <input type="text" name="name" value="<?=$row['name']?>"><br> <input type="hidden" name="id" value="<?=$row['id']?>"> <input type="submit"><br> <a href="?">Return to the list</a> </form> <? include 'tpl_bottom.php' ?> 

list.php

 <? include 'tpl_top.php' ?> <a href="?id=0">Add item</a> <? foreach ($LIST as $row): ?> <li><a href="?id=<?=$row['id']?>"><?=$row['name']?></a> <? endforeach ?> <? include 'tpl_bottom.php' ?> 

ऐसा लगता है कि मेरा दूसरा जवाब सवाल का उद्देश्य याद नहीं रहा।
(यह कोई भी कुछ आवश्यकताओं को पूरा नहीं करता है, लेकिन जैसा कि यह देखा जा सकता है, प्लेसहोल्डर्स को प्रोसेस करने के लिए कोई कार्य निष्पादित किए बिना सुरक्षित समाधान प्राप्त किया जा सकता है, जो कि सुरक्षित प्रश्नों का आधारशिला है)

इसलिए, यहां mysql क्वेरी को सुरक्षित बनाने के लिए संक्षिप्त समाधान पोस्ट करने का दूसरा प्रयास है।

एक फ़ंक्शन जो मैंने बहुत पहले लिखा था और जब तक मैं निगम के मानक OOP- आधारित समाधान में नहीं ले गया तब तक मुझे अच्छी सेवा की।
इसके लिए पीछा करने के लिए 2 गोल थे: सुरक्षा और उपयोग में आसानी

प्लेसहोल्डर्स को कार्यान्वित करके पहले एक प्राप्त किया गया
प्लेसहोल्डर्स और विभिन्न परिणाम प्रकारों को लागू करने के द्वारा हासिल किया गया दूसरा वाला

फ़ंक्शन निश्चित रूप से आदर्श नहीं है कुछ कमियां हैं:

  • कोई % वर्ण को क्वेरी में सीधे रखा जाना चाहिए क्योंकि यह printf सिंटैक्स का उपयोग कर रहा है
  • कोई भी एकाधिक कनेक्शन समर्थित नहीं
  • पहचानकर्ता के लिए कोई प्लेसहोल्डर (साथ ही कई अन्य आसान प्लेसहोल्डर)।
  • फिर से, पहचानकर्ता प्लेसहोल्डर नहीं!"ORDER BY $field" केस को मैन्युअल रूप से संभालना होगा!
  • बेशक एक ओओपी कार्यान्वयन बहुत अधिक लचीला होगा, बदसूरत "मोड" वेरिएबल के साथ ही अन्य आवश्यक तरीकों के बदले साफ भिन्न विधियां हैं।

फिर भी यह अच्छा, सुरक्षित और संक्षिप्त है, पूरे पुस्तकालय को स्थापित करने की कोई आवश्यकता नहीं है।

 function dbget() { /* usage: dbget($mode, $query, $param1, $param2,...); $mode - "dimension" of result: 0 - resource 1 - scalar 2 - row 3 - array of rows */ $args = func_get_args(); if (count($args) < 2) { trigger_error("dbget: too few arguments"); return false; } $mode = array_shift($args); $query = array_shift($args); $query = str_replace("%s","'%s'",$query); foreach ($args as $key => $val) { $args[$key] = mysql_real_escape_string($val); } $query = vsprintf($query, $args); if (!$query) return false; $res = mysql_query($query); if (!$res) { trigger_error("dbget: ".mysql_error()." in ".$query); return false; } if ($mode === 0) return $res; if ($mode === 1) { if ($row = mysql_fetch_row($res)) return $row[0]; else return NULL; } $a = array(); if ($mode === 2) { if ($row = mysql_fetch_assoc($res)) return $row; } if ($mode === 3) { while($row = mysql_fetch_assoc($res)) $a[]=$row; } return $a; } ?> 

उपयोग के उदाहरण

 $name = dbget(1,"SELECT name FROM users WHERE id=%d",$_GET['id']); $news = dbget(3,"SELECT * FROM news WHERE title LIKE %s LIMIT %d,%d", "%$_GET[search]%",$start,$per_page); 

जैसा कि ऊपर दिए गए उदाहरणों से देखा जा सकता है, सभी कोडों में से मुख्य अंतर कभी भी Stackoverflow में पोस्ट किया जाता है, दोनों सुरक्षा और डेटा पुनर्प्राप्ति रूटीन फ़ंक्शन कोड में समझाए जाते हैं। इसलिए, मैन्युअल बाध्यकारी, भागने / उद्धरण या कास्टिंग, साथ ही कोई मैन्युअल डेटा पुनर्प्राप्ति भी नहीं।

अन्य सहायक समारोह के साथ संयुक्त

 function dbSet($fields,$source=array()) { $set = ''; if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`$field`='".mysql_real_escape_string($source[$field])."', "; } } return substr($set, 0, -2); } 

इस तरह इस्तेमाल किया

 $fields = explode(" ","name surname lastname address zip phone regdate"); $_POST['regdate'] = $_POST['y']."-".$_POST['m']."-".$_POST['d']; $sql = "UPDATE $table SET ".dbSet($fields).", stamp=NOW() WHERE id=%d"; $res = dbget(0,$sql, $_POST['id']); if (!$res) { _503;//calling generic 503 error function } 

यह ओपी से उदाहरण के मामले सहित लगभग सभी जरूरतों को कवर कर सकता है