دستور prepare در PHP
دستورات آماده برای مقابله با SQL injection ها بسیار کارآمداند.
دستورات آماده (Prepared) و Bind کردن پارامترها
با استفاده از دستورات آماده یا Prepared، می توانید یک کوئری یکسان را به تعداد دفعات دلخواه با راندمان بالا اجرا نمایید.
نحوه عملکرد دستورات آماده یا Prepared:
- Prepare: با استفاده از این دستور می توانید قالبِ یک کوئری SQL را ایجاد کرده و به پایگاه داده ارسال نمایید. در واقع دلیل استفاده از کلمه قالب در اینجا این است که بجای پارامترهای لازم در کوئری، از علامت سوال (؟) استفاده می کنیم.
مثال (دستور prepare در PHP)
INSERT INTO MyGuests VALUES(?, ?, ?)
- حالا قالب SQL ارسال شده، توسط پایگاه داده، تجزیه و کامپایل می شود و در ادامه بهینه ساز کوئری (query optimization) روی آن اجرا می شود و در نهایت نتیجه کار بدون اجرا در پایگاه داده ذخیره می شود.
- Execute: در ادامه ی اسکریبت، مقادیر لازم را به پارامترهای کوئری مان Bind می کنیم و با استفاده از دستور Execute، کوئری را اجرا می کنیم. اما نکته ای که وجود دارد این است که کوئری ما همچنان در پایگاه داده وجود دارد و می توانیم مجدداً آنرا با پارامترهای جدید اجرا کنیم ...!
روش استفاده از دستورات آماده در مقایسه با اجرای مستقیم کوئری ها دو مزیت اصلی دارد:
- دستورات آماده، زمان تجزیه (parsing) کوئری را کاهش می دهند و این در حالی است که برای مواقعی که قصد داریم یک کوئری را به دفعات اجرا کنیم، این زمان فقط یکبار محاسبه خواهد شد.
- از آنجایی که برای هر بار اجرای کوئری، فقط باید پارامترها را ارسال کنیم، بنابراین پهنای باند کمتری مصرف خواهد شد.
- دستورات آماده برای مقابله با SQL injection ها بسیار کارآمد هستند و این بخاطر استفاده از یک پروتوکول متفاوت برای انتقال مقادیر پارامترهاست.
تزریق SQL یا SQL injection چیست؟ SQL injection زمانی رخ می دهد که شما از کاربر یک ورودی می خواهید ( مثلا نام خانوادگی ، سن و ... ) و کاربر بجای نام، یک دستور MySQL را وارد می نماید و این دستور بدون اطلاع شما بر روی دیتابیس اجرا می شود. مثال (دستور prepare در PHP)$username="''; Delete From users"; نتیجه کد بالا Select From users where usernamr= ''; Delete From users توضیح: همان طور که در کد بالا مشاهده می کنید، ورودی مخرب، باعث می شود که دو کوئری روی پایگاه داده اجرا شود و از آن مهمتر، کوئری دوم است که باعث می شود تا تمام اطلاعات جدول users حذف شود...! |
دستورات آماده یا Prepared در MySQLi
در مثال زیر،نحوه ی استفاده از دستورات آماده یا Prepared و همچنین نحوه ی Bind کردن پارامترها در MySQLi نشان داده شده است:
مثال(MySQLi with Prepared Statements)
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// ایجاد ارتباط به پایگاه داده
$conn = new mysqli($servername, $username, $password, $dbname);
// اطمینان از صحت ارتباط
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// تنظیم کوئری و بایند کردن پارامترها با استفاده از دستورات آماده
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// تنظیم پارامترها و اجرای کوئری
$firstname = "John";
$lastname = "Doe";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
$firstname = "Mary";
$lastname = "Moe";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
$firstname = "Julie";
$lastname = "Dooley";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
echo "New records created successfully";
$stmt->close();
$conn->close();
?>
توضیح مثال بالا:
در کوئری مان می توانیم از علامت سوال (؟) استفاده کنیم، این علامت در ادامه با یک عدد صحیح (integer)، رشته (string)، عدد اعشاری (double) یا داده های با اندازه بزرگ (BLOB - Binary Large OBject) جایگزین خواهد شد.
در ادامه نگاهی به تابع ()bind_param خواهیم انداخت:
با استفاده از تابع ()bind_param، می توانیم پارامترها را به کوئری SQL مان Bind کنیم و به پایگاه داده بگوییم که چه پارامترهایی داریم. همچنین با استفاده از آرگومان اول یعنی "sss"، نوع پارامترها را تعیین می کنیم. کاراکتر s به MySQL می گوید که پارمتر ما از نوع رشته (string) است.
نوع آرگومان ها می تواند یکی از چهار گزینه زیر باشد:
- i - integer
- d - double
- s - string
- b - BLOB
برای هر کدام از آرگومان ها، باید یکی از چهار مقدار بالا را تنظیم کنیم.
زمانی که نوع پارامترها را مشخص می کنیم، ریسک تزریقات SQL یا SQL injections توسط هکرها را به حداقل می رسانیم.
توجه: اگر قصد دارید که داده ی دریافتی از کاربران را در پایگاه داده ذخیره کنید، اعتبارسنجی داده ها یک امر بسیار مهم است. |
دستورات آماده یا Prepared در PDO
در مثال زیر،نحوه ی استفاده از دستورات آماده یا Prepared و همچنین نحوه ی Bind کردن پارامترها در PDO نشان داده شده است:
مثال(PDO with Prepared Statements)
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
try {
//ایجاد ارتباط
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// تنظیم حالت برخورد با خطاها
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// تنظیم کوئری و بایند کردن پارامترها با استفاده از دستورات آماده
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email)
VALUES (:firstname, :lastname, :email)");
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->bindParam(':email', $email);
// تنظیم پارامترها و اجرای کوئری
$firstname = "John";
$lastname = "Doe";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
// تنظیم پارامترها و اجرای کوئری
$firstname = "Mary";
$lastname = "Moe";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
// تنظیم پارامترها و اجرای کوئری
$firstname = "Julie";
$lastname = "Dooley";
$email = "این آدرس ایمیل توسط spambots حفاظت می شود. برای دیدن شما نیاز به جاوا اسکریپت دارید";
$stmt->execute();
echo "New records created successfully";
}
catch(PDOException $e)
{
echo "Error: " . $e->getMessage();
}
$conn = null;
?>
برای مشاهده فیلم ها و آموزش های پروژه محور برنامه نویسی PHP کلیک کنید.
- نوشته شده توسط امیر پهلوان صادق
- بازدید: 28474
دیدگاهها
لطفا جواب بدید: من نمیفهمم، چرا در تابع bind_param، باید در پارامتر اول نوع داده ها رو مشخص کنیم...!؟ مگر نه اینکه هر ستون جدول خودش یه data type دارد.
i - integer
d - double
s - string
b - BLOB
چه معنی میده؟
زمانی که نوع پارامترها را مشخص می کنیم، ریسک تزریقات SQL یا SQL injections توسط هکرها را به حداقل می رسانیم.
عالی بود.
سلام و خسته نباشید ، برای نوع date چه آرگومانی باید استفاده بشه؟
اگه جواب بدین ممنون میشم
با سلام و تشکر.
منظورتون چیه دقیقا؟
در PHP از تابع date برای نمایش تاریخ استفاده میشه. میتونیم نمایش تاریخ رو بر اساس فرمت دلخواه تنظیم کنیم. این فرمت رو میتونید از سایت php.net ببینید.
با عرض سلام و خسته نباشید
ببخشید من مشکلی در استفاده از bind_param دارم که وقتی کد رو اجرا میکنم با این خطا مواجه میشم همه چی رو هم چند بار نگاه کردم مشکلی جایی نداشتم ولی بازم این خطای زیر رو میده:
fatal_error: call to a member function bind_param() on boolean in c:\xampp\htdacs \project\includ es\register.php on line 36
نمیدونم چرا این متد رو نمیشناسه!
سلام
متد ()prepare می تواند یک مقدار false را برگرداند و بخاطر همین باید مقدار برگشتی را چک کنید. شاید نام جدول یا ستون ها در دستور Select و یا قسمت Where صحیح نیست ...!
if ($stmt = $conn->prepare( "SELECT u_id FROM users WHERE u_username=? and u_password=?"))
{
//بایند کردن پارامترها
$stmt->bind_par am("ss", $u_username, $u_password);
...
} از این روش در پروژه رزرو هتل استفاده شده است: www.beyamooz.com/php/339-project-hotel/2594
با سلام و خسته نباشيد خدمت شما و تشكر بابت زحماتتان...ببخش يد توي مثال هاي بالا روش MySQLi Procedural وجود نداره...چرا؟اگه ما به صورت MySQLi Procedural پايگاه داده داشته باشيم چطوري بايد از Prepared استفاده كنيم؟
سلام ممنون، حتماً به لینک زیر برید و مثال Procedural style را بررسی فرمایید:
php.net/manual/en/mysqli.prepare.php