मुझे PHP में mysql_ * फ़ंक्शन का उपयोग क्यों नहीं करना चाहिए?


2502

किसी को mysql_*फ़ंक्शंस का उपयोग क्यों नहीं करना चाहिए इसके लिए तकनीकी कारण क्या हैं ? (जैसे mysql_query(), mysql_connect()याmysql_real_escape_string() )?

मुझे अपनी साइट पर काम करने पर भी कुछ और क्यों इस्तेमाल करना चाहिए?

यदि वे मेरी साइट पर काम नहीं करते हैं, तो मुझे त्रुटि क्यों मिलती है

चेतावनी: mysql_connect (): ऐसी कोई फ़ाइल या निर्देशिका नहीं


इस तरह की त्रुटि: घातक त्रुटि: अनिर्दिष्ट त्रुटि: अपरिभाषित फ़ंक्शन पर कॉल करें mysql_connect () ...
बिमल पॉडेल

21
अकेले से बचने के लिए पर्याप्त कारण है
Sasa1234

जवाबों:


2088

MySQL एक्सटेंशन:

  • सक्रिय विकास के तहत नहीं है
  • है आधिकारिक तौर पर पदावनत (जून 2013 को जारी) पीएचपी 5.5 के रूप में।
  • पूरी तरह से हटा दिया गया हैPHP 7.0 के रूप में (दिसंबर 2015 को जारी)
    • इसका मतलब है कि 31 दिसंबर 2018 तक यह PHP के किसी भी समर्थित संस्करण में मौजूद नहीं है। यदि आप PHP के एक संस्करण का उपयोग कर रहे हैं जो इसका समर्थन करता है, तो आप एक ऐसे संस्करण का उपयोग कर रहे हैं जो सुरक्षा समस्याओं को ठीक नहीं करता है।
  • एक OO इंटरफ़ेस को कम करता है
  • समर्थन नहीं करता है:
    • गैर-अवरुद्ध, अतुल्यकालिक प्रश्न
    • तैयार किए गए बयान या पैरामीटरयुक्त प्रश्न
    • संग्रहित प्रक्रियाएं
    • एकाधिक विवरण
    • लेन-देन
    • "नया" पासवर्ड प्रमाणीकरण विधि (MySQL 5.6 में डिफ़ॉल्ट रूप से; 5.7 में आवश्यक है)
    • MySQL 5.1 या बाद में नई कार्यक्षमता में से कोई भी

चूंकि यह पदावनत है, इसलिए इसका उपयोग करने से आपका कोड कम भविष्य का प्रमाण बन जाता है।

तैयार किए गए कथनों के लिए समर्थन का अभाव विशेष रूप से महत्वपूर्ण है क्योंकि वे अलग-अलग फ़ंक्शन कॉल के साथ मैन्युअल रूप से भागने की तुलना में बाहरी डेटा से बचने के लिए एक स्पष्ट, कम त्रुटि-रहित पद्धति प्रदान करते हैं।

SQL एक्सटेंशन की तुलना देखें ।


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

111
पदावनति जादू की गोली हर कोई नहीं लगता है कि यह लगता है। PHP स्वयं एक दिन नहीं होगी, फिर भी हम आज हमारे निपटान में हमारे पास मौजूद उपकरणों पर भरोसा करते हैं। जब हमें उपकरण बदलने होंगे, हम करेंगे।
ऑर्बिट

133
@LightnessRacesinOrbit - डिप्रेसेशन एक जादू की गोली नहीं है, यह एक झंडा है जो कहता है कि "हम इस बेकार को पहचानते हैं इसलिए हम इसे अधिक समय तक समर्थन नहीं करेंगे"। कोड के बेहतर भविष्य के प्रमाण होने के दौरान पदावनत सुविधाओं से दूर जाने का एक अच्छा कारण है, यह केवल एक (या यहां तक ​​कि मुख्य एक) नहीं है। उपकरण बदलें क्योंकि बेहतर उपकरण हैं, इसलिए नहीं कि आप मजबूर हैं। (और इससे पहले कि आप अपने कोड काम बंद कर दिया है और कल फिक्सिंग की जरूरत है, जो नए उपकरण सीखने के लिए सबसे खराब समय है) आप नए लोगों को सीखने के लिए मजबूर कर रहे हैं, इसका मतलब है कि आप नया नहीं सीख रहे हैं।
क्वेंटिन

18
एक बात जो मैंने तैयार बयानों की कमी के बारे में नहीं देखी है वह है प्रदर्शन का मुद्दा। हर बार जब आप एक बयान जारी करते हैं, तो कुछ को इसे संकलित करना होगा ताकि MySQL डेमन इसे समझ सके। इस API के साथ, यदि आप एक ही क्वेरी के 200,000 को लूप में जारी करते हैं, तो यह 200,000 बार क्वेरी को समझने के लिए MySQL के लिए संकलित किया जाना है। तैयार किए गए कथनों के साथ, इसे एक बार संकलित किया जाता है, और फिर मानों को संकलित SQL में परिचालित किया जाता है।
गोल्डेंटोआ

20
@symcbean, यह निश्चित रूप से तैयार कथनों का समर्थन नहीं करता है । यह वास्तव में मुख्य कारण है कि यह क्यों निकाला गया है। बिना (उपयोग में आसान) तैयार किए गए कथन mysql एक्सटेंशन अक्सर SQL इंजेक्शन के हमलों का शिकार हो जाते हैं।
20

1287

PHP MySQL से जुड़ने के लिए तीन अलग-अलग API प्रदान करता है। ये हैं mysql(PHP 7 के रूप में हटा दिया गया) mysqli, और PDOएक्सटेंशन।

mysql_*कार्यों में बहुत लोकप्रिय हुआ करते थे, लेकिन उनके उपयोग अब और प्रोत्साहित नहीं किया जाता है। प्रलेखन टीम डेटाबेस सुरक्षा स्थिति पर चर्चा कर रही है, और उपयोगकर्ताओं को आमतौर पर उपयोग किए जाने वाले ext / mysql एक्सटेंशन से दूर जाने के लिए शिक्षित कर रही है, यह इसका हिस्सा है (चेक php.internals: deprecating ext / mysql )।

और बाद में पीएचपी डेवलपर टीम उत्पन्न करने के लिए निर्णय लिया गया है E_DEPRECATEDकि क्या के माध्यम से, जब उपयोगकर्ता MySQL से कनेक्ट त्रुटियों mysql_connect(), mysql_pconnect()या में बनाया अंतर्निहित कनेक्शन कार्यक्षमता ext/mysql

ext/mysqlगया था आधिकारिक तौर पर पीएचपी 5.5 के रूप में पदावनत किया गया है पीएचपी 7 के रूप में निकाल दिया

रेड बॉक्स देखें?

जब आप किसी mysql_*फंक्शन मैनुअल पेज पर जाते हैं, तो आपको एक लाल बॉक्स दिखाई देता है, यह समझाते हुए कि इसे अब इस्तेमाल नहीं किया जाना चाहिए।

क्यों


इससे दूर जाना ext/mysqlन केवल सुरक्षा के बारे में है, बल्कि MySQL डेटाबेस की सभी विशेषताओं तक पहुंच के बारे में भी है।

ext/mysqlMySQL 3.23 के लिए बनाया गया था और तब से केवल बहुत कुछ अतिरिक्त मिला है, जबकि ज्यादातर इस पुराने संस्करण के साथ संगतता रखते हुए जो कोड को बनाए रखने के लिए थोड़ा कठिन बनाता है। अनुपलब्ध सुविधाएँ जो ext/mysqlइसमें शामिल नहीं हैं: ( PHP मैनुअल से )।

mysql_*फ़ंक्शन का उपयोग न करने का कारण :

  • सक्रिय विकास के तहत नहीं
  • PHP 7 के रूप में हटाया गया
  • एक OO इंटरफ़ेस को कम करता है
  • गैर-अवरुद्ध, अतुल्यकालिक प्रश्नों का समर्थन नहीं करता है
  • तैयार कथनों या पैरामीटरयुक्त प्रश्नों का समर्थन नहीं करता है
  • संग्रहीत प्रक्रियाओं का समर्थन नहीं करता है
  • कई बयानों का समर्थन नहीं करता है
  • लेन-देन का समर्थन नहीं करता है
  • MySQL 5.1 में सभी कार्यक्षमता का समर्थन नहीं करता है

क्वेंटिन के उत्तर से उद्धृत बिंदु से ऊपर

तैयार किए गए कथनों के लिए समर्थन का अभाव विशेष रूप से महत्वपूर्ण है क्योंकि वे अलग-अलग फ़ंक्शन कॉल के साथ मैन्युअल रूप से भागने की तुलना में बाहरी डेटा से बचने और उद्धृत करने की एक स्पष्ट, कम त्रुटि प्रवण विधि प्रदान करते हैं।

SQL एक्सटेंशन की तुलना देखें ।


दबाना चेतावनियों को दबाने

कोड में बदला जा रहा है, वहीं MySQLi/ PDO, E_DEPRECATEDस्थापना करके त्रुटियों को दबा दिया जा सकता है error_reportingमें php.ini बाहर करने के लिएE_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

ध्यान दें कि यह अन्य अपक्षय चेतावनी को भी छिपाएगा , जो कि, MySQL के अलावा अन्य चीजों के लिए हो सकता है। ( PHP मेनुअल से )

लेख PDO बनाम MySQLi: आपको किसका उपयोग करना चाहिए? द्वारा डेजन Marjanovic आप का चयन करने के लिए मदद मिलेगी।

और एक बेहतर तरीका है PDO, और मैं अब एक सरल PDOट्यूटोरियल लिख रहा हूं ।


एक सरल और छोटा पीडीओ ट्यूटोरियल


Q. मेरे दिमाग में पहला सवाल था: `PDO` क्या है?

A. " पीडीओ - PHP डेटा ऑब्जेक्ट्स - एक डेटाबेस एक्सेस लेयर है जो कई डेटाबेस तक पहुँच की एक समान विधि प्रदान करता है।"

वैकल्पिक शब्द


MySQL से कनेक्ट करना

mysql_*फ़ंक्शन के साथ या हम इसे पुराने तरीके से कह सकते हैं (PHP 5.5 और इसके बाद के संस्करण में पदावनत)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

के साथ PDO: आपको बस एक नई PDOवस्तु बनाने की जरूरत है । कंस्ट्रक्टर डेटाबेस स्रोत PDOके कंस्ट्रक्टर को निर्दिष्ट करने के लिए मापदंडों को स्वीकार करता है, ज्यादातर चार पैरामीटर लेता है जो DSN(डेटा स्रोत का नाम) हैं और वैकल्पिक रूप से username,password

यहाँ मुझे लगता है कि आप सभी को छोड़कर सभी परिचित हैं DSN; इस में नया है PDO। A DSNमूल रूप से विकल्पों का एक तार है जो बताता है कि PDOकिस चालक का उपयोग करना है, और विवरण का कनेक्शन। आगे के संदर्भ के लिए, PDO MySQL DSN की जाँच करें ।

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

नोट: आप भी उपयोग कर सकते हैं charset=UTF-8, लेकिन कभी-कभी यह एक त्रुटि का कारण बनता है, इसलिए इसका उपयोग करना बेहतर हैutf8

यदि कोई कनेक्शन त्रुटि है, तो यह एक PDOExceptionऑब्जेक्ट को फेंक देगा जिसे Exceptionआगे संभालने के लिए पकड़ा जा सकता है ।

अच्छा पढ़ा : कनेक्शन और कनेक्शन प्रबंधन and

आप चौथे पैरामीटर में सरणी के रूप में कई ड्राइवर विकल्पों में भी पास कर सकते हैं। मैं उस पैरामीटर को पारित करने की सलाह देता हूं जो PDOअपवाद मोड में डालता है। क्योंकि कुछ PDOड्राइवर देशी तैयार बयानों का समर्थन नहीं करते हैं, इसलिए PDOतैयारी का अनुकरण करता है। यह आपको मैन्युअल रूप से इस अनुकरण को सक्षम करने की सुविधा भी देता है। देशी सर्वर-साइड तैयार बयानों का उपयोग करने के लिए, आपको इसे स्पष्ट रूप से सेट करना चाहिए false

दूसरा है तैयार एमुलेशन को बंद करना जो MySQLकि डिफ़ॉल्ट रूप से ड्राइवर में सक्षम है , लेकिन PDOसुरक्षित रूप से उपयोग करने के लिए एमुलेशन तैयार करना बंद कर देना चाहिए ।

मैं बाद में बताऊंगा कि क्यों एमुलेशन तैयार करना बंद कर देना चाहिए। कारण जानने के लिए कृपया इस पोस्ट को देखें

यदि आप किसी पुराने संस्करण का उपयोग कर रहे हैं तो यह केवल प्रयोग करने योग्य है MySQL जिसकी मैंने सिफारिश नहीं की है।

नीचे एक उदाहरण है कि आप इसे कैसे कर सकते हैं:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password',
              array(PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

क्या हम पीडीओ निर्माण के बाद विशेषताएँ निर्धारित कर सकते हैं?

हां , हम setAttributeविधि के साथ पीडीओ निर्माण के बाद कुछ विशेषताओं को भी सेट कर सकते हैं :

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

गलती संभालना


त्रुटि से निपटने में बहुत आसान PDOहै mysql_*

उपयोग करते समय एक सामान्य अभ्यास mysql_*है:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

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

PDOएक बेहतर समाधान प्रदान करता है: अपवाद। क्या हम कुछ के साथ क्या PDOएक में लपेटा जाना चाहिए try- catchब्लॉक। हम PDOत्रुटि मोड विशेषता सेट करके तीन त्रुटि मोड में से एक में मजबूर कर सकते हैं । तीन त्रुटि हैंडलिंग मोड नीचे हैं।

  • PDO::ERRMODE_SILENT। यह केवल त्रुटि कोड सेट कर रहा है और mysql_*जहां आप प्रत्येक परिणाम की जाँच करते हैं और फिर $db->errorInfo();त्रुटि विवरण प्राप्त करने के लिए देखना चाहिए के रूप में बहुत ज्यादा कार्य करता है ।
  • PDO::ERRMODE_WARNINGउठाएँ E_WARNING। (रन-टाइम चेतावनियाँ (गैर-घातक त्रुटियाँ)। स्क्रिप्ट का निष्पादन रुका नहीं है।)
  • PDO::ERRMODE_EXCEPTION: अपवादों को फेंको। यह पीडीओ द्वारा उठाए गए एक त्रुटि का प्रतिनिधित्व करता है। आपको PDOExceptionअपने स्वयं के कोड से नहीं फेंकना चाहिए । PHP में अपवादों के बारे में अधिक जानकारी के लिए अपवाद देखें । यह बहुत पसंद है or die(mysql_error());, जब यह पकड़ा नहीं जाता है। लेकिन इसके विपरीत or die(), PDOExceptionअगर आप ऐसा करने के लिए चुनते हैं , तो इसे पकड़ा जा सकता है और इनायत से नियंत्रित किया जा सकता है।

अच्छा पढ़ें :

पसंद:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

और तुम में लपेट कर सकते हैं try- catchनीचे दिए:

try {
    //Connect as appropriate as above
    $db->query('hi'); //Invalid query!
} 
catch (PDOException $ex) {
    echo "An Error occured!"; //User friendly message/message you want to show to user
    some_logging_function($ex->getMessage());
}

आपको अभी try- catchअभी नहीं संभालना है । आप इसे किसी भी समय उचित रूप से पकड़ सकते हैं, लेकिन मैं दृढ़ता से आपको उपयोग करने की सलाह देता हूं try- catchPDOसामान को कॉल करने वाले फ़ंक्शन के बाहर इसे पकड़ने के लिए भी अधिक समझदारी हो सकती है :

function data_fun($db) {
    $stmt = $db->query("SELECT * FROM table");
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
    data_fun($db);
}
catch(PDOException $ex) {
    //Here you can handle error and show message/perform action you want.
}

इसके अलावा, आप इसे संभाल or die()सकते हैं या हम जैसे कह सकते हैं mysql_*, लेकिन यह वास्तव में विविध होगा। आप उत्पादन में खतरनाक त्रुटि संदेशों को बदल सकते हैं display_errors offऔर अपनी त्रुटि लॉग को पढ़ सकते हैं।

अब, ऊपर सब बातों को पढ़ने के बाद, तो आप शायद सोच रहे हैं: क्या बिल्ली है कि जब मैं सिर्फ सरल झुकाव शुरू करना चाहते हैं SELECT, INSERT, UPDATE, या DELETEबयान? चिंता मत करो, यहाँ हम चलते हैं:


डेटा का चयन करना

पीडीओ छवि का चयन करें

तो आप क्या कर रहे हैं mysql_*:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
    echo $row['field1'];
}

अब PDOआप इस तरह कर सकते हैं:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['field1'];
}

या

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

नोट : यदि आप नीचे दी गई विधि ( query()) का उपयोग कर रहे हैं , तो यह विधि एक PDOStatementवस्तु लौटाती है । इसलिए यदि आप परिणाम प्राप्त करना चाहते हैं, तो इसे ऊपर की तरह उपयोग करें।

<?php
foreach($db->query('SELECT * FROM table') as $row) {
    echo $row['field1'];
}

पीडीओ डेटा में, यह ->fetch()आपके स्टेटमेंट हैंडल की एक विधि के माध्यम से प्राप्त किया जाता है । लाने के लिए कॉल करने से पहले, सबसे अच्छा तरीका पीडीओ को बता रहा है कि आप डेटा कैसे प्राप्त करना चाहते हैं। नीचे के भाग में मैं इसे समझा रहा हूँ।

फ़ोड़ने का काम

नोट के उपयोग PDO::FETCH_ASSOCमें fetch()और fetchAll()इसके बाद के संस्करण कोड। यह PDOपंक्तियों को कुंजी के रूप में फ़ील्ड नामों के साथ एक सहयोगी सरणी के रूप में वापस करने के लिए कहता है। कई अन्य फ़िच मोड भी हैं जिन्हें मैं एक-एक करके समझाता हूँ।

सबसे पहले, मैं समझाता हूं कि कैसे प्राप्त करना है:

 $stmt->fetch(PDO::FETCH_ASSOC)

उपरोक्त में, मैं उपयोग कर रहा हूं fetch()। आप भी उपयोग कर सकते हैं:

  • PDOStatement::fetchAll() - परिणाम सेट पंक्तियों के सभी युक्त एक सरणी देता है
  • PDOStatement::fetchColumn() - परिणाम सेट की अगली पंक्ति से एक एकल कॉलम लौटाता है
  • PDOStatement::fetchObject() - अगली पंक्ति को लाता है और इसे एक वस्तु के रूप में लौटाता है।
  • PDOStatement::setFetchMode() - इस स्टेटमेंट के लिए डिफॉल्ट लिंच मोड सेट करें

अब मैं लाने के लिए मोड:

  • PDO::FETCH_ASSOC: आपके परिणाम सेट में दिए गए कॉलम नाम से अनुक्रमित एक सरणी देता है
  • PDO::FETCH_BOTH (डिफ़ॉल्ट): आपके परिणाम सेट में दिए गए दोनों कॉलम नाम और 0-अनुक्रमित कॉलम नंबर द्वारा अनुक्रमित एक सरणी देता है

और भी विकल्प हैं! PDOStatementFetch प्रलेखन में उन सभी के बारे में पढ़ें

पंक्ति गणना प्राप्त करना :

mysql_num_rowsलौटी हुई पंक्तियों की संख्या प्राप्त करने के लिए उपयोग करने के बजाय , आप एक PDOStatementऐसा कर सकते हैं rowCount(), जैसे:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

अंतिम सम्मिलित आईडी प्राप्त करना

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

सम्मिलित करें और अद्यतन या हटाएँ बयान

सम्मिलित करें और PDO छवि को अपडेट करें

हम जो mysql_*कार्य कर रहे हैं वह है:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

और pdo में, यह वही काम कर सकता है:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

उपरोक्त क्वेरी में PDO::execSQL कथन निष्पादित करें और प्रभावित पंक्तियों की संख्या लौटाता है।

सम्मिलित करें और हटाएं बाद में कवर किया जाएगा।

उपरोक्त विधि केवल तभी उपयोगी है जब आप क्वेरी में परिवर्तनशील का उपयोग नहीं कर रहे हैं। लेकिन जब आपको किसी प्रश्न में एक चर का उपयोग करने की आवश्यकता होती है, तो कभी भी उपरोक्त की तरह प्रयास न करें और तैयार कथन या पैरामीटर किए गए कथन के लिए वहाँ है।


तैयार विवरण

प्रश्न: एक तैयार कथन क्या है और मुझे उनकी आवश्यकता क्यों है?
A. एक तैयार बयान एक पूर्व संकलित SQL स्टेटमेंट है जिसे केवल सर्वर पर डेटा भेजकर कई बार निष्पादित किया जा सकता है।

एक तैयार कथन का उपयोग करने का विशिष्ट कार्य इस प्रकार है ( विकिपीडिया तीन 3 बिंदु से उद्धृत ):

  1. तैयार करें : स्टेटमेंट टेम्प्लेट एप्लिकेशन द्वारा बनाया गया है और डेटाबेस प्रबंधन प्रणाली (DBMS) को भेजा गया है। कुछ मानों को अनिर्दिष्ट छोड़ दिया जाता है, जिन्हें पैरामीटर, प्लेसहोल्डर या बाइंड चर ( ?नीचे लेबल ) कहा जाता है:

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. DBMS पर्सेंट करता है, कंपाइल करता है, और स्टेटमेंट टेम्प्लेट पर क्वेरी ऑप्टिमाइज़ेशन करता है, और रिजल्ट को बिना एक्सेप्ट किए स्टोर करता है।

  3. निष्पादन : बाद के समय में, मापदंडों के लिए एप्लिकेशन आपूर्ति (या बाइंड) मूल्यों, और DBMS कथन को निष्पादित करता है (संभवतः परिणाम लौटाता है)। एप्लिकेशन विवरण को कई बार निष्पादित कर सकता है क्योंकि यह विभिन्न मूल्यों के साथ चाहता है। इस उदाहरण में, यह पहले पैरामीटर के 1.00लिए और दूसरे पैरामीटर के लिए 'ब्रेड' की आपूर्ति कर सकता है ।

आप अपने SQL में प्लेसहोल्डर्स को शामिल करके एक तैयार स्टेटमेंट का उपयोग कर सकते हैं। प्लेसहोल्डर के बिना मूल रूप से तीन व्यक्ति हैं (इसके ऊपर एक के साथ चर की कोशिश न करें), एक अनाम प्लेसहोल्डर के साथ, और एक नामित प्लेसहोल्डर्स के साथ।

प्र। अब, प्लेसहोल्डर्स का नाम क्या है और मैं उनका उपयोग कैसे करूं?
नामांकित प्लेसहोल्डर। प्रश्नवाचक चिन्ह के स्थान पर एक बृहदान्त्र से पहले वर्णनात्मक नामों का उपयोग करें। हम नाम स्थान धारक की स्थिति / मूल्य के बारे में परवाह नहीं करते हैं:

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

आप एग्जीक्यूटिव ऐरे का उपयोग करके भी बाँध सकते हैं:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

OOPदोस्तों के लिए एक और अच्छी विशेषता यह है कि नामित प्लेसहोल्डर्स सीधे आपके डेटाबेस में ऑब्जेक्ट्स को सम्मिलित करने की क्षमता रखते हैं, यह मानते हुए कि नामित फ़ील्ड से गुण मेल खाते हैं। उदाहरण के लिए:

class person {
    public $name;
    public $add;
    function __construct($a,$b) {
        $this->name = $a;
        $this->add = $b;
    }

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

प्र। अब, अनाम प्लेसहोल्डर क्या हैं और मैं उनका उपयोग कैसे करूं?
चलो एक उदाहरण है:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

तथा

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

उपरोक्त में, आप ?एक नाम स्थान धारक की तरह नाम के बजाय उन देख सकते हैं । अब पहले उदाहरण में, हम विभिन्न प्लेसहोल्डर्स ( $stmt->bindValue(1, $name, PDO::PARAM_STR);) को वेरिएबल प्रदान करते हैं । फिर, हम उन प्लेसहोल्डर्स को मान असाइन करते हैं और स्टेटमेंट निष्पादित करते हैं। दूसरे उदाहरण में, पहला ऐरे तत्व पहले ?और दूसरे से दूसरे तक जाता है ?

ध्यान दें : अनाम प्लेसहोल्डर में हमें उस सरणी में तत्वों के उचित क्रम का ध्यान रखना चाहिए जिसे हम PDOStatement::execute()विधि में पास कर रहे हैं ।


SELECT, INSERT, UPDATE, DELETEतैयार प्रश्नों

  1. SELECT:

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  2. INSERT:

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
  3. DELETE:

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
  4. UPDATE:

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();

ध्यान दें:

हालाँकि PDOऔर / या MySQLiपूरी तरह से सुरक्षित नहीं हैं। उत्तर की जाँच करें क्या SQL इंजेक्शन को रोकने के लिए PDO पर्याप्त विवरण तैयार करते हैं? ircmaxell द्वारा । इसके अलावा, मैं उनके उत्तर से कुछ अंश उद्धृत कर रहा हूं:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));

15
उपरोक्त पढ़ी गई बातों का अच्छे से जिक्र करना चाहिए: तैयार किया गया कथन किसी भी तरह के सार्थक उपयोग को दूर करता है IN (...) construct
यूजेन रीक

24
सवाल यह था कि "मुझे PHP में mysql_ * फ़ंक्शन का उपयोग क्यों नहीं करना चाहिए"। यह उत्तर, प्रभावशाली और उपयोगी जानकारी से भरा हुआ है, WAY स्कोप से बाहर चला जाता है और @trejder की तरह कहता है - 10 में से 8 लोग उस सूचना को केवल इसलिए याद करने जा रहे हैं क्योंकि उनके पास काम करने की कोशिश में खर्च करने के लिए 4 घंटे नहीं हैं यह। यह कहीं अधिक मूल्यवान होगा और इसका उपयोग कई, अधिक सटीक, प्रश्नों के उत्तर के रूप में किया जाएगा।
एलेक्स मैकमिलन

Persoanlly मैं mysqli और PDO पसंद करते हैं। लेकिन मरने से निपटने के लिए, मैंने अपवाद के विकल्प की कोशिश की, function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx();यह अपवाद फेंकने के लिए काम करता है।
kuldeep.kamboj

आप Doesn't support non-blocking, asynchronous queriesmysql_ का उपयोग नहीं करने के कारण के रूप में सूचीबद्ध करते हैं - आपको पीडीओ का उपयोग नहीं करने के लिए एक कारण के रूप में भी सूची देनी चाहिए, क्योंकि पीडीओ उस का समर्थन नहीं करता है। (लेकिन MySQLi इसका समर्थन करती है)
hanshenrik

क्या चारसेट utf8mb4_unicode_ci का उपयोग करना संभव है क्योंकि मेरे पास एक डेटाबेस है जो इसका उपयोग कर रहा है?
रयान स्टोन

301

सबसे पहले, आइए मानक टिप्पणी के साथ शुरू करें जो हम सभी को देते हैं:

कृपया, mysql_*नए कोड में कार्यों का उपयोग न करें । वे अब बनाए नहीं हैं और आधिकारिक तौर पर पदावनत हैंलाल बॉक्स देखें? इसके बजाय तैयार किए गए कथनों के बारे में जानें, और PDO या MySQLi का उपयोग करें- यह लेख आपको यह तय करने में मदद करेगा कि कौन सा। यदि आप पीडीओ चुनते हैं, तो यहां एक अच्छा ट्यूटोरियल है

आइए, इस वाक्य के माध्यम से चलते हैं, और समझाते हैं:

  • वे अब बनाए नहीं हैं, और आधिकारिक तौर पर पदावनत हैं

    इसका मतलब है कि PHP समुदाय धीरे-धीरे इन बहुत पुराने कार्यों के लिए समर्थन छोड़ रहा है। वे PHP के भविष्य (हाल के) संस्करण में मौजूद नहीं होने की संभावना है! इन फ़ंक्शंस का निरंतर उपयोग आपके कोड को भविष्य में (ऐसा नहीं) तोड़ सकता है।

    नया! - ext / mysql अब आधिकारिक तौर पर PHP 5.5 के रूप में पदावनत हो गया है!

    नई! PHP 7 में ext / mysql को हटा दिया गया है

  • इसके बजाय, आपको तैयार किए गए कथनों को सीखना चाहिए

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

    अधिक जानकारी के लिए देखें मैं PHP में SQL इंजेक्शन को कैसे रोक सकता हूं?

  • रेड बॉक्स देखें?

    जब आप किसी भी mysql फ़ंक्शन मैनुअल पेज पर जाते हैं, तो आपको एक लाल बॉक्स दिखाई देता है, यह समझाते हुए कि इसे अब और उपयोग नहीं किया जाना चाहिए।

  • PDO या MySQLi का उपयोग करें

    बेहतर, अधिक मजबूत और अच्छी तरह से निर्मित विकल्प हैं, पीडीओ - पीएचपी डाटाबेस ऑब्जेक्ट , जो डेटाबेस इंटरैक्शन के लिए एक पूर्ण ओओपी दृष्टिकोण प्रदान करता है, और MySQLi , जो एक MySQL विशिष्ट सुधार है।


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

4
@ कामिल: यह सच है, लेकिन यह वास्तव में एक कारण नहीं है कि आपको इसका उपयोग क्यों नहीं करना चाहिए। इसका उपयोग न करने का कारण यह है कि यह प्राचीन, असुरक्षित, आदि है :)
मदारा का भूत

4
@Mario - PHP देवों के पास एक प्रक्रिया है, और उन्होंने अभी औपचारिक रूप से 5.5 के रूप में ext / mysql को हटाने के पक्ष में मतदान किया है। यह अब एक काल्पनिक मुद्दा नहीं है।
एसडीसी

2
PDO या MySQLi जैसी सिद्ध तकनीक के साथ कुछ अतिरिक्त पंक्तियों को जोड़ना अभी भी उपयोग की आसानी PHP की पेशकश करता है। मैं डेवलपर के लिए आशा करता हूं कि वह / वह जानती है कि इन भगवान-भयानक mysql_ * को देखकर किसी भी ट्यूटोरियल वास्तव में पाठ से अलग हो जाता है, और ओपी को बताना चाहिए कि 10 साल पहले इस तरह का कोड soooo है- और उससे सवाल करना चाहिए ट्यूटोरियल की प्रासंगिकता, भी!
फ्रेडइनवेब्यू

1
उत्तर में संक्षिप्त रूप से क्या उल्लेख किया जाना चाहिए: तैयार कथन किसी भी सार्थक उपयोग को दूर कर देता है IN (...) construct
यूजेन रीक

217

उपयोग में आसानी

विश्लेषणात्मक और सिंथेटिक कारणों का पहले ही उल्लेख किया गया था। नए लोगों के लिए दिनांकित mysql_ फ़ंक्शन का उपयोग करने से रोकने के लिए अधिक महत्वपूर्ण प्रोत्साहन है।

समकालीन डेटाबेस APIs का उपयोग करना आसान है।

यह ज्यादातर बाध्य पैरामीटर है जो कोड को सरल बना सकता है। और उत्कृष्ट ट्यूटोरियल के साथ (जैसा कि ऊपर देखा गया है) पीडीओ के लिए संक्रमण अत्यधिक कठिन नहीं है।

हालांकि, एक बार में बड़ा कोड आधार फिर से शुरू करने में समय लगता है। इस मध्यवर्ती विकल्प के लिए Raison d'être:

समतुल्य pdo_ * mysql_ * के स्थान पर कार्य करता है

< Pdo_mysql.php > का उपयोग करके आप न्यूनतम प्रयास के साथ पुराने mysql_ फ़ंक्शन से स्विच कर सकते हैं । यह pdo_फंक्शन रैपर जोड़ता है जो उनके mysql_समकक्षों को प्रतिस्थापित करता है।

  1. बस प्रत्येक मंगलाचरण स्क्रिप्ट में जो डेटाबेस के साथ बातचीत करना है। include_once("pdo_mysql.php");

  2. हर जगहmysql_ फ़ंक्शन उपसर्ग निकालें और इसे बदलें ।pdo_

    • mysql_connect() हो जाता है pdo_connect()
    • mysql_query() हो जाता है pdo_query()
    • mysql_num_rows() हो जाता है pdo_num_rows()
    • mysql_insert_id() हो जाता है pdo_insert_id()
    • mysql_fetch_array() हो जाता है pdo_fetch_array()
    • mysql_fetch_assoc() हो जाता है pdo_fetch_assoc()
    • mysql_real_escape_string() हो जाता है pdo_real_escape_string()
    • और इसी तरह...

  3. आपका कोड समान रूप से काम करेगा और फिर भी अधिकतर समान दिखाई देगा:

    include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }

एट वॉयला।
आपका कोड PDO का उपयोग कर रहा है
अब वास्तव में इसका उपयोग करने का समय आ गया है।

बाउंड पैरामीटर का उपयोग करना आसान हो सकता है

आपको बस एक कम अनिर्दिष्ट एपीआई की आवश्यकता है।

pdo_query()बाध्य मापदंडों के लिए बहुत ही सुविधाजनक समर्थन जोड़ता है। पुराने कोड को बदलना सीधा है:

SQL स्ट्रिंग से बाहर अपने चर ले जाएँ।

  • उन्हें कॉमा सीमांकित फ़ंक्शन मापदंडों के रूप में जोड़ें pdo_query()
  • ?प्लेसहोल्डर के रूप में प्रश्न चिह्न लगाएं जहां चर पहले थे।
  • 'एकल उद्धरणों से छुटकारा पाएं जो पहले स्ट्रिंग मान / चर को संलग्न करते थे।

लाभ लंबा कोड के लिए और अधिक स्पष्ट हो जाता है।

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

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

साथ ?प्लेसहोल्डर लागू किया आप उस के साथ परेशान करने के लिए नहीं है:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

याद रखें कि pdo_ * अभी भी या तो अनुमति देता है ।
बस एक चर से बच नहीं है और इसे एक ही क्वेरी में बांधें।

  • प्लेसहोल्डर सुविधा इसके पीछे असली पीडीओ द्वारा प्रदान की जाती है।
  • इस प्रकार :namedबाद में प्लेसहोल्डर सूचियों की भी अनुमति दी ।

अधिक महत्वपूर्ण बात आप किसी भी प्रश्न के पीछे $ _REQUEST [] चर को सुरक्षित रूप से पारित कर सकते हैं। जब सबमिट किए गए <form>फ़ील्ड डेटाबेस संरचना से मेल खाते हैं तो यह और भी कम है:

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

इतनी सरलता। लेकिन आइए कुछ और पुनर्लेखन सलाह और तकनीकी कारणों पर वापस जाएं, जिनसे आप छुटकारा पाना चाहते हैंmysql_ बचना और बच सकते हैं।

किसी भी ओल्डस्कूल को ठीक करें या निकालें sanitize() फ़ंक्शन को

एक बार जब आप सभी mysql_कॉल को pdo_queryबाध्य परिमों के साथ बदल देते हैं , तो सभी अनावश्यक हटा देंpdo_real_escape_string कॉल ।

विशेष रूप से आप किसी भी ठीक करना चाहिए sanitizeया cleanया filterThisया clean_dataकार्य के रूप में एक या किसी अन्य में दिनांकित ट्यूटोरियल द्वारा विज्ञापित:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

यहाँ पर ज्यादातर चमकता हुआ बग प्रलेखन की कमी है। अधिक महत्वपूर्ण रूप से फ़िल्टरिंग का क्रम बिल्कुल गलत क्रम में था।

  • सही क्रम यह होता: डिप्रेस्डली stripslashesइन इंसर्मोस्ट कॉल के रूप में, फिर trim, बाद में strip_tags, htmlentitiesआउटपुट संदर्भ के लिए, और केवल अंतिम _escape_stringरूप से इसके अनुप्रयोग को सीधे SQL इंटरसेप्टरिंग से पहले होना चाहिए।

  • लेकिन पहले कदम के रूप में सिर्फ कॉल से छुटकारा मिलता है_real_escape_string

  • sanitize()यदि डेटाबेस और एप्लिकेशन प्रवाह HTML-संदर्भ-सुरक्षित स्ट्रिंग्स की अपेक्षा करते हैं, तो आपको अपने शेष फ़ंक्शन को अभी के लिए रखना पड़ सकता है । एक टिप्पणी जोड़ें कि यह केवल HTML के लिए लागू होता है, इसलिए।

  • स्ट्रिंग / मान से निपटने को पीडीओ और इसके मानकीकृत कथनों में सौंपा गया है।

  • यदि stripslashes()आपके स्वच्छता समारोह में कोई उल्लेख था , तो यह उच्च स्तर के निरीक्षण का संकेत हो सकता है।

    मैजिक_क्ोट्स पर ऐतिहासिक नोट। उस सुविधा को ठीक से चित्रित किया गया है। यह अक्सर असफल सुरक्षा के रूप में गलत तरीके से चित्रित किया जाता है सुविधा के । लेकिन मैजिक_क्वॉट्स एक असफल सुरक्षा विशेषता के रूप में टेनिस बॉल पोषण स्रोत के रूप में विफल रहे हैं। यह बस उनका उद्देश्य नहीं था।

    PHP2 / FI में मूल कार्यान्वयन ने इसे स्पष्ट रूप से पेश किया "बस उद्धरणों को स्वचालित रूप से बचाना आसान हो जाएगा ताकि फॉर्म डेटा को सीधे msql प्रश्नों में पास किया जा सके "। विशेष रूप से यह mSQL के साथ उपयोग करने के लिए आकस्मिक रूप से सुरक्षित था , जैसा कि केवल ASCII समर्थित था।
    तब PHP3 / Zend ने MySQL के लिए Magic_quotes को पुन: प्रस्तुत किया और इसे गलत बताया। लेकिन मूल रूप से यह सिर्फ एक सुविधा की सुविधा थी , सुरक्षा का इरादा नहीं था।

कैसे तैयार बयान अलग हैं

जब आप एसक्यूएल प्रश्नों में स्ट्रिंग चर देते हैं, तो यह आपके लिए अनुसरण करने के लिए अधिक जटिल नहीं होता है। यह MySQL के लिए कोड और डेटा को फिर से अलग करने का भी विलक्षण प्रयास है।

SQL इंजेक्शन बस तब होता है जब डेटा कोड में ब्लीड हो जाता है संदर्भ है। एक डेटाबेस सर्वर बाद में हाजिर नहीं हो सकता है जहां PHP मूल रूप से चर inbetween क्वेरी खंडों को चिपकाता है।

बाध्य मापदंडों के साथ आप अपने PHP कोड में SQL कोड और SQL- संदर्भ मानों को अलग करते हैं। लेकिन यह फिर से पर्दे के पीछे नहीं जाता है (PDO :: EMULATE_PREPARES को छोड़कर)। आपके डेटाबेस को unwaried SQL कमांड और 1: 1 चर मान प्राप्त होते हैं।

हालांकि यह जवाब तनावपूर्ण है कि आपको छोड़ने के पठनीयता लाभों के बारे में ध्यान देना चाहिए mysql_ । इस दृश्यमान और तकनीकी डेटा / कोड पृथक्करण के कारण कभी-कभी प्रदर्शन लाभ भी होता है (बस अलग-अलग मानों के साथ INSERTs)।

उस बंधन से सावधान रहें अभी भी सभी के खिलाफ एक जादू एक-स्टॉप समाधान नहीं है SQL इंजेक्शन के । यह डेटा / मूल्यों के लिए सबसे आम उपयोग को संभालता है। लेकिन डायनामेलिस्ट कॉलम नाम / टेबल आइडेंटिफ़ायर, डायनेमिक क्लॉज़ कंस्ट्रक्शन या सिर्फ प्लेन ऐरे वैल्यू लिस्ट की मदद नहीं ले सकता।

हाइब्रिड पीडीओ का उपयोग

ये pdo_*आवरण कार्य एक कोडिंग के अनुकूल स्टॉप-गैप एपीआई बनाते हैं। (यह बहुत ज्यादा हो MYSQLIसकता है अगर यह idiosyncratic फ़ंक्शन हस्ताक्षर शिफ्ट के लिए नहीं था)। वे अधिकांश समय वास्तविक पीडीओ को भी उजागर करते हैं।
नए pdo_ फ़ंक्शन नामों का उपयोग करने पर रीराइटिंग को रोकना नहीं है। आप एक-एक करके प्रत्येक pdo_query () को एक सादे $ pdo-> तैयार () -> निष्पादित () कॉल में बदल सकते हैं।

हालाँकि इसे फिर से सरल बनाना शुरू करना सबसे अच्छा है। उदाहरण के लिए सामान्य परिणाम प्राप्त करना:

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

सिर्फ एक अगुण पुनरावृत्ति के साथ प्रतिस्थापित किया जा सकता है:

foreach ($result as $row) {

या बेहतर अभी तक एक प्रत्यक्ष और पूर्ण सरणी पुनर्प्राप्ति:

$result->fetchAll();

आप पीडीओ या mysql_ की तुलना में ज्यादातर मामलों में अधिक उपयोगी चेतावनी प्राप्त करेंगे, आमतौर पर विफल प्रश्नों के बाद प्रदान करते हैं।

अन्य विकल्प

इसलिए इस उम्मीद ने कुछ व्यावहारिक कारणों और छोड़ने के लिए एक उपयोगी मार्ग की कल्पना की mysql_

बस में स्विच कर रहा हूं यह काफी कटौती नहीं करता है। pdo_query()इस पर भी एक दृश्य है।

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

हालांकि यह सबसे सरल-चीज़-कि-संभवतः-कार्य श्रेणी के लिए योग्य है, यह अभी भी बहुत प्रयोगात्मक कोड है। मैंने इसे सप्ताहांत में ही लिखा था। हालांकि विकल्पों में से एक बहुतायत है। PHP डेटाबेस अमूर्त के लिए बस Google और थोड़ा ब्राउज़ करें। ऐसे कार्यों के लिए हमेशा उत्कृष्ट पुस्तकालय रहे हैं और रहेंगे।

यदि आप अपने डेटाबेस इंटरैक्शन को और सरल बनाना चाहते हैं, तो पेरिस / इडियोरम जैसे मैपर्स एक कोशिश के लायक हैं। जैसे कोई भी अब और जावास्क्रिप्ट में ब्लैंड डोम का उपयोग नहीं करता है, आपको आजकल एक कच्चे डेटाबेस इंटरफ़ेस को बंद करने की आवश्यकता नहीं है।


8
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);समारोह के साथ सावधान रहें - यानी:pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');
rickyduck

@ टम ज़रूर, हालांकि यह बहुत बनाए रखा नहीं है (0.9.2 अंतिम था), आप एक जीवाश्म खाता बना सकते हैं , विकी में जोड़ सकते हैं या बग रिपोर्ट दर्ज कर सकते हैं (पंजीकरण IIRC के बिना)।
मारियो

pdo_real_escape_string() <- क्या यह भी एक वास्तविक कार्य है, मुझे इसके लिए कोई दस्तावेज नहीं मिल सकता है? कृपया इसके लिए एक स्रोत पोस्ट करें।
रयान स्टोन

144

mysql_कार्य:

  1. पुराने हैं - वे किसी भी अधिक बनाए नहीं रखते हैं
  2. आपको दूसरे डेटाबेस बैकएंड पर आसानी से जाने की अनुमति नहीं है
  3. इसलिए तैयार कथनों का समर्थन न करें
  4. एसक्यूएल इंजेक्शन भेद्यता के लिए अग्रणी, प्रश्नों का निर्माण करने के लिए कार्यक्रम का उपयोग करने के लिए प्रोग्रामर को प्रोत्साहित करें

18
# 2 भी उतना ही सच हैmysqli_
जैसे कि अयिंगल

16
निष्पक्ष होने के लिए, एसक्यूएल बोली में भिन्नता को देखते हुए, यहां तक ​​कि पीडीओ आपको निश्चितता के किसी भी डिग्री के साथ # 2 नहीं देता है। आपको उसके लिए एक उचित ORM आवरण की आवश्यकता होगी।
एसडीसी

mysql_*समारोह नए पीएचपी संस्करणों के लिए mysqlnd कार्यों में एक खोल रहे हैं। तो भले ही पुराने क्लाइंट लाइब्रेरी को और अधिक बनाए नहीं रखा जाता है, mysqlnd बनाए रखा जाता है :)
हैकर

समस्या यह नहीं है कि कई वेब-होस्टिंग प्रदाता पुराने php संस्करण के कारण डिजाइन की ऐसी वस्तु-उन्मुख शैली का समर्थन कर सकते हैं
राजू yourPepe

@RajuGujarati तो एक वेब होस्ट मिल सकता है जो कर सकते हैं। यदि आपका वेब होस्ट नहीं करता है, तो संभावना बहुत अधिक है कि वे अपने सर्वर पर हमलों के लिए असुरक्षित हैं।
अलनीतक

106

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

  • गैर-अवरुद्ध, अतुल्यकालिक प्रश्न
  • संग्रहीत परिणाम कई परिणाम लौटाते हैं
  • एन्क्रिप्शन (एसएसएल)
  • दबाव

यदि आपको उनकी आवश्यकता है - ये कोई शक नहीं कि तकनीकी कारणों से कुछ अधिक स्टाइलिश और आधुनिक दिखने की दिशा में mysql एक्सटेंशन से दूर जाना होगा।

फिर भी, कुछ गैर-तकनीकी मुद्दे भी हैं, जो आपके अनुभव को थोड़ा कठिन बना सकते हैं

  • आधुनिक PHP संस्करणों के साथ इन कार्यों का आगे उपयोग पदावनत स्तर के नोटिस को बढ़ाएगा। उन्हें बस बंद किया जा सकता है।
  • दूर के भविष्य में, उन्हें संभवतः डिफ़ॉल्ट PHP बिल्ड से हटाया जा सकता है। कोई बड़ी बात भी नहीं है, क्योंकि mydsql ext को PECL में स्थानांतरित कर दिया जाएगा और हर होस्टर्स को इसके साथ PHP संकलित करने में खुशी होगी, क्योंकि वे उन ग्राहकों को खोना नहीं चाहते हैं जिनकी साइटें दशकों से काम कर रही थीं।
  • Stackoverflow समुदाय से मजबूत प्रतिरोध। आप इन ईमानदार कार्यों का उल्लेख करते हैं, तो आपको बताया जाता है कि वे सख्त वर्जित हैं।
  • एक औसत PHP उपयोगकर्ता होने के नाते, सबसे अधिक संभावना है कि इन कार्यों का उपयोग करने का आपका विचार त्रुटि-रहित और गलत है। बस इन सभी कई ट्यूटोरियल और मैनुअल के कारण जो आपको गलत तरीके सिखाते हैं। स्वयं कार्य नहीं - मुझे इस पर जोर देना है - लेकिन जिस तरह से उनका उपयोग किया जाता है।

यह बाद वाला मुद्दा एक समस्या है।
लेकिन, मेरी राय में, प्रस्तावित समाधान भी बेहतर नहीं है।
यह मुझे बहुत आदर्शवादी सपना लगता है कि उन सभी PHP उपयोगकर्ता सीखेंगे कि एक बार में एसक्यूएल प्रश्नों को ठीक से कैसे प्रबंधित किया जाए। सबसे अधिक संभावना है कि वे सिर्फ mysql_ * को mysqli_ * में बदल देंगे, यांत्रिक रूप से, उसी दृष्टिकोण को छोड़कर । विशेष रूप से क्योंकि mysqli तैयार बयानों का उपयोग अविश्वसनीय दर्दनाक और परेशान करता है।
यह उल्लेख नहीं करने के लिए कि देशी तैयार बयान एसक्यूएल इंजेक्शन से बचाने के लिए पर्याप्त नहीं हैं , और न तो mysqli और न ही पीडीओ एक समाधान प्रदान करता है।

इसलिए, इस ईमानदार विस्तार से लड़ने के बजाय, मैं गलत तरीकों से लड़ने और लोगों को सही तरीके से शिक्षित करना पसंद करूंगा।

इसके अलावा, कुछ झूठे या गैर-महत्वपूर्ण कारण हैं, जैसे

  • संग्रहीत प्रक्रियाओं का समर्थन नहीं करता (हम mysql_query("CALL my_proc");उम्र के लिए उपयोग कर रहे थे )
  • लेनदेन का समर्थन नहीं करता (ऊपर जैसा है)
  • एकाधिक विवरणों का समर्थन नहीं करता (जिनकी उन्हें आवश्यकता है?)
  • सक्रिय विकास के तहत नहीं (तो क्या? यह आपको किसी भी व्यावहारिक तरीके से प्रभावित करता है ?)
  • OO इंटरफ़ेस को खो देता है (एक को बनाना कई घंटों का मामला है)
  • तैयार स्टेटमेंट या पैरामीटर क्वेरी का समर्थन नहीं करता है

आखिरी एक दिलचस्प बिंदु है। हालाँकि mysql ext देशी मूली कथनों का समर्थन नहीं करता है , लेकिन सुरक्षा के लिए इनकी आवश्यकता नहीं होती है। हम मैन्युअल रूप से हैंडल किए गए प्लेसहोल्डर्स (जैसे पीडीओ करते हैं) का उपयोग करके आसानी से नकली तैयार किए गए बयान दे सकते हैं:

function paraQuery()
{
    $args  = func_get_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);
    $result = mysql_query($query);
    if (!$result)
    {
        throw new Exception(mysql_error()." [$query]");
    }
    return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

वॉइला , सब कुछ पैरामीटर और सुरक्षित है।

लेकिन ठीक है, अगर आपको मैनुअल में लाल बॉक्स पसंद नहीं है, तो चुनाव की समस्या पैदा होती है: mysqli या PDO?

खैर, उत्तर इस प्रकार होगा:

  • यदि आप एक डेटाबेस अमूर्त परत का उपयोग करने और एक बनाने के लिए एपीआई की तलाश करने की आवश्यकता को समझते हैं , तो mysqli एक बहुत अच्छा विकल्प है, क्योंकि यह वास्तव में कई mysql- विशिष्ट सुविधाओं का समर्थन करता है।
  • अगर, PHP के अधिकांश लोगों की तरह, आप एप्लिकेशन कोड में कच्चे एपीआई कॉल का सही उपयोग कर रहे हैं (जो अनिवार्य रूप से गलत अभ्यास है) - पीडीओ एकमात्र विकल्प है , क्योंकि यह एक्सटेंशन केवल एपीआई नहीं बल्कि एक सेमी-डीएएल होने का दिखावा करता है, अभी भी अधूरा है, लेकिन कई महत्वपूर्ण विशेषताएं प्रदान करता है, उनमें से दो पीडीओ गंभीर रूप से mysqli से प्रतिष्ठित करता है:

    • mysqli के विपरीत, PDO प्लेसहोल्डर्स को मूल्य से बाँध सकता है , जो डायनेमिक रूप से निर्मित प्रश्नों को बिना किसी गड़बड़ कोड के कई स्क्रीन के बिना संभव बनाता है।
    • mysqli के विपरीत, PDO हमेशा एक सामान्य सामान्य सरणी में क्वेरी परिणाम लौटा सकता है, जबकि mysqli केवल mysqlnd स्थापनाओं पर ही कर सकता है।

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

फिर भी, एक्सटेंशन के बारे में बात करने वाले हर व्यक्ति को मैसकली और पीडीओ के बारे में 2 महत्वपूर्ण तथ्य याद आ रहे हैं :

  1. तैयार बयान चांदी की गोली नहीं है । ऐसे गतिशील पहचानकर्ता हैं जो तैयार किए गए कथनों का उपयोग करके बाध्य नहीं हो सकते हैं। अज्ञात संख्या में मापदंडों के साथ गतिशील प्रश्न हैं जो क्वेरी के निर्माण को एक कठिन काम बनाते हैं।

  2. आवेदन कोड में न तो mysqli_ * और न ही पीडीओ फ़ंक्शन दिखाई देने चाहिए।
    वहाँ उनके और अनुप्रयोग कोड के बीच एक अमूर्त परत होना चाहिए , जो बाध्यकारी, पाशन, त्रुटि से निपटने, आदि के सभी गंदे काम को अंदर करेगा, जिससे एप्लिकेशन कोड DRY और साफ हो जाएगा। खासतौर पर डायनामिक क्वेरी बिल्डिंग जैसे जटिल मामलों के लिए।

तो, बस पीडीओ या mysqli पर स्विच करना पर्याप्त नहीं है। एक को अपने कोड में कच्चे एपीआई कार्यों को कॉल करने के बजाय एक ORM, या एक क्वेरी बिल्डर, या जो भी डेटाबेस अमूर्त वर्ग का उपयोग करना होगा।
और इसके विपरीत - यदि आपके पास अपने एप्लिकेशन कोड और mysql एपीआई के बीच एक अमूर्त परत है - यह वास्तव में कोई फर्क नहीं पड़ता कि किस इंजन का उपयोग किया जाता है। आप तब तक mysql ext का उपयोग कर सकते हैं जब तक कि यह पदावनत न हो जाए और फिर आसानी से अपने एब्स्ट्रैक्शन क्लास को किसी अन्य इंजन में फिर से लिख दें, सभी एप्लिकेशन कोड बरकरार रहे।

यहाँ पर कुछ उदाहरण दिए गए हैं, जो यह बताने के लिए कि यह अमूर्त वर्ग कैसे होना चाहिए:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

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

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

सामान्य पीडीओ आवेषण के साथ इसकी तुलना करें, जब हर एक क्षेत्र का नाम छह से दस बार दोहराया जा रहा है - इन सभी कई नामित प्लेसहोल्डर्स, बाइंडिंग और क्वेरी परिभाषाओं में।

एक और उदाहरण:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

आप इस तरह के व्यावहारिक मामले को संभालने के लिए पीडीओ के लिए एक उदाहरण पा सकते हैं।
और यह बहुत ही चिंताजनक और सबसे अधिक असुरक्षित होगा।

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


20
mysql_*कमजोरियों को बहुत आसान बना देता है। चूंकि PHP का उपयोग बहुत सारे नौसिखिए उपयोगकर्ताओं द्वारा किया जाता है, इसलिए mysql_*यह व्यवहार में सक्रिय रूप से हानिकारक है, भले ही सिद्धांत रूप में इसे एक अड़चन के बिना उपयोग किया जा सकता है।
मदारा का भूत

4
everything is parameterized and safe- इसे मानकीकृत किया जा सकता है, लेकिन आपका फ़ंक्शन वास्तविक तैयार विवरणों का उपयोग नहीं करता है ।
unnb us

6
Not under active developmentकेवल उस बना-बनाया '0.01%' के लिए ही कैसे ? यदि आप इस स्टैंड-स्टिल फ़ंक्शन के साथ कुछ बनाते हैं, तो एक वर्ष में अपने mysql- संस्करण को अपडेट करें और एक गैर-कार्य प्रणाली के साथ हवा दें, मुझे यकीन है कि उस '0.01%' में अचानक बहुत सारे लोग हैं। मैं कहूँगा कि deprecatedऔर not under active developmentनिकटता से संबंधित हैं। आप कह सकते हैं कि इसके लिए "कोई [योग्य] कारण" नहीं है, लेकिन तथ्य यह है कि जब विकल्पों के बीच एक विकल्प की पेशकश की जाती है, no active developmentतो लगभग उतना ही बुरा होगा जितना deprecatedमैं कहूंगा?
नन्हा

1
@ मंदराउचिहा: क्या आप बता सकते हैं कि कमजोरियों का आना कितना आसान है? विशेष रूप से उन मामलों में जहां वही कमजोरियां पीडीओ या मायएससीआई को प्रभावित नहीं करती हैं ... क्योंकि मैं एक एकल के बारे में नहीं जानता हूं जो आप बोलते हैं।
ircmaxell

4
@ShaquinTrifonoff: निश्चित रूप से, यह तैयार किए गए कथनों का उपयोग नहीं करता है। लेकिन न तो पीडीओ , जो ज्यादातर लोग MySQLi पर सलाह देते हैं। इसलिए मुझे यकीन नहीं है कि यहाँ एक महत्वपूर्ण प्रभाव है। उपरोक्त कोड (थोड़ी और पार्सिंग के साथ) पीडीओ क्या करता है जब आप डिफ़ॉल्ट रूप से एक स्टेटमेंट तैयार करते हैं ...
ircmaxell

97

कई कारण हैं, लेकिन शायद सबसे महत्वपूर्ण यह है कि वे कार्य असुरक्षित प्रोग्रामिंग प्रथाओं को प्रोत्साहित करते हैं क्योंकि वे तैयार किए गए बयानों का समर्थन नहीं करते हैं। तैयार किए गए बयान SQL इंजेक्शन के हमलों को रोकने में मदद करते हैं।

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

इसमें तैयार किए गए कथनों का उपयोग करना PDOया mysqliऐसा करना ताकि इन प्रकार की प्रोग्रामिंग त्रुटियों को बनाना अधिक कठिन हो।


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

5
लेकिन, एक बार फिर असुरक्षा, mysql_ * कार्यों की एक अंतर्निहित समस्या नहीं है, बल्कि गलत उपयोग की समस्या है।
अगामेन्नुस

2
@Agamemnus समस्या यह है कि mysql_ * उस "गलत उपयोग" को लागू करना आसान बनाता है, खासकर अनुभवहीन प्रोग्रामर के लिए। तैयार किए गए कथनों को लागू करने वाले पुस्तकालय उस प्रकार की त्रुटि करना कठिन बनाते हैं।
ट्रॉट

75

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

एक उदाहरण के रूप में, कोई "enhzflep); drop table users"उपयोगकर्ता नाम के रूप में उपयोग कर सकता है । पुराने कार्य प्रति क्वेरी में कई कथनों को निष्पादित करने की अनुमति देंगे, इसलिए ऐसा कुछ बुरा बुर्जर पूरी तालिका को हटा सकता है।

यदि कोई mysqli के पीडीओ का उपयोग करता है, तो उपयोगकर्ता-नाम एंड-अप हो जाएगा "enhzflep); drop table users"

देखें bobby-tables.com


10
The old functions will allow executing of multiple statements per query- नहीं, वे नहीं करेंगे। इस तरह का इंजेक्शन ext / mysql के साथ संभव नहीं है - PHP और MySQL के साथ इस तरह का इंजेक्शन संभव है जब MySQLi और mysqli_multi_query()फ़ंक्शन का उपयोग किया जाता है। जिस तरह का इंजेक्शन ext / mysql और unescaped स्ट्रिंग्स के साथ संभव ' OR '1' = '1है वह डेटाबेस से डेटा निकालने की तरह है जो सुलभ होने के लिए नहीं था। कुछ स्थितियों में उप-प्रश्नों को इंजेक्ट करना संभव है, हालांकि इस तरह से डेटाबेस को संशोधित करना अभी भी संभव नहीं है।
डेवग्रैंडम डेन्स 30'12

64

यह उत्तर यह दिखाने के लिए लिखा गया है कि PHP उपयोगकर्ता-सत्यापन कोड को खराब तरीके से लिखने के लिए कितना तुच्छ है, यह (और क्या उपयोग करता है) ये हमले एक सुरक्षित तैयार विवरण के साथ पुराने MySQL कार्यों को कैसे और कैसे बदलें - Stackververflow उपयोगकर्ताओं (शायद बहुत से प्रतिनिधि के साथ) नए उपयोगकर्ताओं को अपने कोड में सुधार करने के लिए सवाल पूछ रहे हैं।

सबसे पहले, कृपया इस परीक्षण mysql डेटाबेस बनाने के लिए स्वतंत्र महसूस करें (मैंने मेरा प्रीप कहा है):

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

उस काम के साथ, हम अपने PHP कोड पर जा सकते हैं।

मान लें कि निम्न स्क्रिप्ट एक वेबसाइट पर एक व्यवस्थापक के लिए सत्यापन प्रक्रिया है (यदि आप इसे कॉपी और परीक्षण के लिए उपयोग करते हैं तो सरलीकृत लेकिन काम करना है:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

पहली नज़र में काफी वैध लगता है।

उपयोगकर्ता को एक लॉगिन और पासवर्ड दर्ज करना होगा, है ना?

शानदार, निम्नलिखित में दर्ज न करें:

user: bob
pass: somePass

और सबमिट करें।

आउटपुट इस प्रकार है:

You could not be verified. Please try again...

उत्तम! उम्मीद के मुताबिक काम करते हुए, अब वास्तविक उपयोगकर्ता नाम और पासवर्ड आज़माएं:

user: Fluffeh
pass: mypass

गजब का! हाय-फाइव ऑल राउंड, कोड ने एक व्यवस्थापक को सही ढंग से सत्यापित किया। यह एकदम सही है!

असल में ऐसा नहीं है। कहते हैं कि उपयोगकर्ता एक चतुर व्यक्ति है। कहते हैं, वह व्यक्ति मैं हूं।

निम्नलिखित में दर्ज करें:

user: bob
pass: n' or 1=1 or 'm=m

और आउटपुट है:

The check passed. We have a verified admin!

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

तो, जवाब में, यह क्यों है कि आप कम से कम हो रहे हैं।

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

select id, userid, pass from users where userid='$user' and pass='$pass'

यह क्वेरी है, लेकिन जब हम उन चरों को प्रतिस्थापित करते हैं जो हमारे द्वारा उपयोग किए जाने वाले वास्तविक इनपुट के साथ आते हैं, तो हमें निम्नलिखित मिलते हैं:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

देखें कि मैंने अपने "पासवर्ड" का निर्माण कैसे किया ताकि यह पहले पासवर्ड के चारों ओर एक उद्धरण को बंद कर दे, फिर एक पूरी तरह से नई तुलना शुरू करें? फिर बस सुरक्षा के लिए, मैंने एक और "स्ट्रिंग" जोड़ा ताकि एकल कोट बंद हो जाए जैसा कि हमारे पास मूल रूप से कोड में था।

हालाँकि, यह अब आप पर चिल्ला रहे लोगों के बारे में नहीं है, यह आपको अपने कोड को अधिक सुरक्षित बनाने का तरीका दिखाने के बारे में है।

ठीक है, तो क्या गलत हुआ, और हम इसे कैसे ठीक कर सकते हैं?

यह एक क्लासिक एसक्यूएल इंजेक्शन हमला है। उस मामले के लिए सबसे सरल में से एक। आक्रमण वैक्टर के पैमाने पर, यह एक टैंक पर हमला करने वाला बच्चा है - और जीत।

तो, हम आपके पवित्र व्यवस्थापक अनुभाग की रक्षा कैसे करते हैं और इसे अच्छा और सुरक्षित बनाते हैं? पहली बात यह है कि वास्तव में पुराने और पदावनत किए गए mysql_*कार्यों का उपयोग करना बंद करना होगा । मुझे पता है, आपने एक ट्यूटोरियल का अनुसरण किया था जिसे आपने ऑनलाइन पाया था और यह काम करता है, लेकिन यह पुराना है, यह पुराना है और कुछ ही मिनटों के अंतराल में, मैंने इसे पिछले हिस्से को बिना किसी पसीने के तोड़ दिया है।

अब, आपके पास mysqli_ या PDO का उपयोग करने के बेहतर विकल्प हैं । मैं व्यक्तिगत रूप से पीडीओ का बहुत बड़ा प्रशंसक हूं, इसलिए मैं इस उत्तर के बाकी हिस्सों में पीडीओ का उपयोग करूंगा। वहाँ समर्थक और चोर हैं, लेकिन व्यक्तिगत रूप से मुझे लगता है कि समर्थक दूर है con जीत। यह कई डेटाबेस इंजनों में पोर्टेबल है - चाहे आप MySQL या Oracle का उपयोग कर रहे हैं या केवल खूनी के बारे में कुछ भी - बस कनेक्शन स्ट्रिंग को बदलकर, इसमें सभी फैंसी विशेषताएं हैं जिन्हें हम उपयोग करना चाहते हैं और यह अच्छा और साफ है। मुझे साफ पसंद है।

अब, उस कोड पर फिर से एक नज़र डालते हैं, इस बार पीडीओ ऑब्जेक्ट का उपयोग करते हुए लिखा गया है:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

प्रमुख अंतर यह है कि अधिक mysql_*कार्य नहीं हैं । यह सब एक पीडीओ ऑब्जेक्ट के माध्यम से किया जाता है, दूसरे, यह एक तैयार कथन का उपयोग कर रहा है। अब, क्या आप पहले से पूछ रहे हैं? यह क्वेरी को चलाने से पहले डेटाबेस को बताने का एक तरीका है, जो क्वेरी हम चलाने जा रहे हैं। इस मामले में, हम डेटाबेस को बताते हैं: "हाय, मैं आईडी, उपयोगकर्ता नाम चाहने वाले एक स्टेटमेंट को चलाने जा रहा हूं और टेबल उपयोगकर्ताओं से पास करूंगा जहां उपयोगकर्ता एक चर है और पास भी एक चर है।"

फिर, निष्पादित विवरण में, हम डेटाबेस को सभी चर के साथ एक सरणी पास करते हैं जो अब यह अपेक्षा करता है।

परिणाम शानदार हैं। पहले से उन उपयोगकर्ता नाम और पासवर्ड संयोजनों को आजमाएं:

user: bob
pass: somePass

उपयोगकर्ता सत्यापित नहीं था। बहुत बढ़िया।

कैसा रहेगा:

user: Fluffeh
pass: mypass

ओह, मैं बस थोड़ा उत्तेजित हो गया, यह काम किया: चेक पास हुआ। हमारे पास एक सत्यापित व्यवस्थापक है!

अब, डेटा को आज़माने की कोशिश करते हैं जो कि हमारे छोटे सत्यापन प्रणाली को प्राप्त करने की कोशिश करने के लिए एक चतुर चाप में प्रवेश करेगा:

user: bob
pass: n' or 1=1 or 'm=m

इस बार, हम निम्नलिखित प्राप्त करते हैं:

You could not be verified. Please try again...

यही कारण है कि आपको प्रश्न पोस्ट करते समय चिल्लाया जा रहा है - यह इसलिए है क्योंकि लोग देख सकते हैं कि आपके कोड को भी कोशिश करने पर बायपास किया जा सकता है। कृपया, इस प्रश्न का उपयोग करें और अपने कोड को बेहतर बनाने के लिए उत्तर दें, इसे अधिक सुरक्षित बनाने के लिए और वर्तमान में होने वाले कार्यों का उपयोग करने के लिए।

अंत में, यह कहना नहीं है कि यह सही कोड है। कई और चीजें हैं जो आप इसे सुधार सकते हैं, उदाहरण के लिए हैशेड पासवर्ड का उपयोग करें, सुनिश्चित करें कि जब आप डेटाबेस में संवेदी जानकारी संग्रहीत करते हैं, तो आप इसे सादे पाठ में संग्रहीत नहीं करते हैं, सत्यापन के कई स्तर हैं - लेकिन वास्तव में, यदि आप बस अपने पुराने इंजेक्शन प्रवण कोड को इस में बदल देंगे, आप अच्छे कोड लिखने के तरीके के साथ WELL हो जाएंगे - और यह तथ्य कि आपने इसे अभी तक प्राप्त कर लिया है और अभी भी पढ़ रहे हैं, मुझे आशा है कि आप इस प्रकार को लागू नहीं करेंगे अपनी वेबसाइटों और अनुप्रयोगों को लिखते समय कोड, लेकिन आप बाहर जा सकते हैं और उन अन्य चीजों पर शोध कर सकते हैं, जिनका मैंने अभी उल्लेख किया है - और बहुत कुछ। सबसे अच्छा कोड आप लिख सकते हैं, न कि सबसे बुनियादी कोड जो मुश्किल से कार्य करता है।


2
आपके उत्तर के लिए धन्यवाद! मेरे +1 है! यह ध्यान देने योग्य है कि mysql_*अपने आप में असुरक्षित नहीं है, लेकिन यह खराब ट्यूटोरियल और उचित स्टेटमेंट एपीआई एपीआई की कमी के माध्यम से असुरक्षित कोड को बढ़ावा देता है।
मदारा का भूत

2
पासवर्ड अनहैश, ओह हॉरर! विस्तृत विवरण के लिए = oP अन्यथा +1।
गुप्तकालीन

33

MySQL एक्सटेंशन तीन में से सबसे पुराना है और यह मूल तरीका था जिसे डेवलपर्स MySQL के साथ संवाद करने के लिए इस्तेमाल करते थे। यह विस्तार अब PHP और MySQL दोनों की नई रिलीज़ में किए गए सुधारों के कारण अन्य दो विकल्पों के पक्ष में पदावनत किया जा रहा है ।

  • MySQLi MySQL डेटाबेस के साथ काम करने के लिए 'बेहतर' एक्सटेंशन है। यह उन सुविधाओं का लाभ उठाता है जो MySQL सर्वर के नए संस्करणों में उपलब्ध हैं, डेवलपर के लिए फ़ंक्शन-ओरिएंटेड और ऑब्जेक्ट-ओरिएंटेड इंटरफ़ेस दोनों को उजागर करता है और कुछ अन्य निफ्टी चीजों को करता है।

  • पीडीओ एक एपीआई प्रदान करता है जो सबसे अधिक कार्यक्षमता को समेकित करता है जो पहले प्रमुख डेटाबेस एक्सेस एक्सटेंशन, जैसे MySQL, PostgreSQL, SQLite, MSSQL, आदि में फैला हुआ था। इंटरफ़ेस प्रोग्रामर के लिए डेटाबेस कनेक्शन, क्वेरी और क्वेरी के साथ काम करने के लिए उच्च-स्तरीय ऑब्जेक्ट को उजागर करता है। परिणाम सेट, और निम्न-स्तरीय ड्राइवर डेटाबेस सर्वर के साथ संचार और संसाधन संचालन करते हैं। बहुत सारी चर्चा और काम पीडीओ में जा रहे हैं और इसे आधुनिक, पेशेवर कोड में डेटाबेस के साथ काम करने का उपयुक्त तरीका माना जाता है।


21

मुझे उपर्युक्त उत्तर वास्तव में लम्बे लगते हैं, इसलिए संक्षेप में:

Mysqli एक्सटेंशन के कई लाभ हैं, mysql एक्सटेंशन में महत्वपूर्ण वृद्धि:

  • ऑब्जेक्ट-ओरिएंटेड इंटरफ़ेस
  • तैयार स्टेटमेंट के लिए समर्थन
  • एकाधिक विवरणों के लिए समर्थन
  • लेन-देन के लिए समर्थन
  • बढ़ी डिबगिंग क्षमताओं
  • एंबेडेड सर्वर का समर्थन

स्रोत: MySQLi ओवरव्यू


जैसा कि ऊपर दिए गए उत्तरों में बताया गया है, mysql के विकल्प mysqli और PDO (PHP Data Objects) हैं।

  • API सर्वर-साइड रेडी स्टेट्स का समर्थन करता है: MYSQLi और PDO द्वारा समर्थित
  • एपीआई क्लाइंट-साइड तैयार स्टेटमेंट का समर्थन करता है: केवल पीडीओ द्वारा समर्थित
  • एपीआई संग्रहीत प्रक्रियाओं का समर्थन करता है: MySQLi और PDO दोनों
  • एपीआई मल्टीपल स्टेटमेंट और सभी MySQL 4.1+ कार्यक्षमता का समर्थन करता है - MySQLi द्वारा समर्थित है और ज्यादातर पीडीओ द्वारा भी

MySQLi और PDO दोनों को PHP 5.0 में पेश किया गया था, जबकि MySQL को PHP 3.0 से पहले पेश किया गया था। ध्यान देने वाली बात यह है कि MySQL को PHP5.x में शामिल किया गया है, हालाँकि बाद के संस्करणों में हटा दिया गया है।


2
आपका उत्तर बहुत लंबा है, जबकि असली सारांश "mysql ext नहीं है"। वह सब है
आपका कॉमन सेंस

1
@YourCommonSense मेरा जवाब है कि mysqli ने mysql को क्यों प्रतिस्थापित किया। यह कहने की बात नहीं है कि मैसकली आज भी मौजूद है, इसलिए इसका उपयोग करें .. हर कोई जानता है कि!
एनी मेनन

1
खैर, इस तथ्य के अलावा कि किसी ने यह नहीं पूछा कि क्यों mysqli ने mysql को प्रतिस्थापित किया, यह इस प्रश्न का उत्तर नहीं देता है। यह जवाब देता है कि क्यों mysqli पेश किया गया था। लेकिन यह स्पष्ट नहीं करता है कि mysql और mysqli को समानांतर में रहने की अनुमति क्यों नहीं दी गई
Your Common Sense

@YourCommonSense भी ओपी का सवाल है "मुझे अपनी साइट पर काम करने पर भी कुछ और क्यों इस्तेमाल करना चाहिए?" और यही कारण है कि मैंने परिवर्तनों और सुधारों की ओर संकेत किया। आप अन्य सभी उत्तरों को देख सकते हैं वे लंबे हैं इसलिए मैंने सोचा कि मुझे इसे संक्षेप में प्रस्तुत करना चाहिए।
अनी मेनन

6

mysql_*Mysqli या PDO का उपयोग करके लगभग सभी कार्यों को परिभाषित करना संभव है । बस उन्हें अपने पुराने PHP एप्लिकेशन के शीर्ष पर शामिल करें, और यह PHP7 पर काम करेगा। मेरा समाधान यहाँ

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($host, $user, $pass) {
    return mysql_connect($host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}

अपने समाधान के लिए लिंक दिखाने के बजाय, कृपया उन्हें उत्तर के रूप में यहां जोड़ें।
अमरनाथ

1

जो फ़ंक्शन इस के समान हैं mysql_connect(), mysql_query()प्रकार पिछले संस्करण हैं PHP (यानी PHP 4) फ़ंक्शन और अब उपयोग में नहीं हैं।

इन्हें बदल दिया जाता है mysqli_connect(), mysqli_query()इसी तरह नवीनतम PHP5 में।

त्रुटि के पीछे यही कारण है।


2
PHP 5 अब 2 वर्षों से अधिक नवीनतम नहीं है।
मदारा का घोस्ट

1

MySQL PHP 5.5.0 में पदावनत हो गया, और PHP 7.0.0 में हटा दिया गया। एक बड़े और पुराने एप्लिकेशन के लिए, प्रत्येक फ़ंक्शन को खोजना और बदलना मुश्किल है।

हम नीचे चल रहे प्रत्येक कोड के लिए एक आवरण फ़ंक्शन बनाकर MySQL फ़ंक्शन का उपयोग कर सकते हैं। यहाँ क्लिक करें


-9

mysql_ * फ़ंक्शन को पदावनत किया गया था ( PHP 5.5 के रूप में ) इस तथ्य को देखते हुए कि बेहतर कार्यों और कोड संरचनाओं को विकसित किया गया था। तथ्य यह है कि फ़ंक्शन को पदावनत किया गया था, का अर्थ है कि प्रदर्शन और सुरक्षा के संदर्भ में इसे बेहतर बनाने में कोई और प्रयास नहीं किया जाएगा, जिसका अर्थ है कि यह भविष्य का प्रमाण कम है

यदि आपको और कारण चाहिए:

  • mysql_ * फ़ंक्शन तैयार कथनों का समर्थन नहीं करता है।
  • mysql_ * फ़ंक्शंस मापदंडों के बंधन का समर्थन नहीं करते हैं।
  • mysql_ * फ़ंक्शन ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग के लिए कार्यक्षमता की कमी है।
  • सूची चलती जाती है ...

18
यह उत्तर पुराना है। इसके अलावा, यह उन उत्तरों के लिए कुछ भी उपयोगी नहीं है जो पहले से मौजूद हैं।
आपका कॉमन सेंस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.