نکات کاربردی در پی اچ پی پارت 3


21. داده ها را با استفاده از php filter اعتبارسنجی (validate) نمایید:

حتما قبلا از عبارات باقاعده یا regex برای اعتبارسنجی داده ها نظیر ایمیل، آدرس ip و غیره استفاده کرده اید. اکنون می خواهیم به شما روش دیگری که به نسبت کاراتر هست را معرفی کنیم.

php یک افزونه به نام php filter دارد. با ابزاری که این extension در اختیار شما قرار می دهد قادر خواهید بود به راحتی صحت و اعتبار داده ها بسنجید.

22. اعمال بررسی نوع (force type checking):

$amount = intval( $_GET['amount'] );  $rate = (int) $_GET['rate'];  

یک روش خوب است که توصیه می کنیم همیشه انجام دهید.

23. درج خطاهای مهم php در یک فایل با استفاده از تابع set_error_handler():

می توانید با استفاده از تابع set_error_handler() یک متد جهت مدیرت خطاها به صورت اختصاصی تنظیم نمایید. توصیه می شود خطاهای مهم رخ داده در صفحه را در یک فایل به منظور ثبت گزارش درج (write) نمایید.

24. در مدیریت آرایه هایی که حجم زیادی را در حافظه اشغال می کنند، دقت نمایید:

لازم است در مدیریت متغیرهای حجیم، آرایه ها و رشته های سنگین و طولانی، دقت کنید. یک خطای رایج که توسعه دهندگان مرتکب می شوند، این است که از متغیر نام برده، یک کپی گرفته و سپس به علت کمبود حافظه، با خطای مهلک در اپلیکیشن مواجه می شوند. پیغام خطا بدین شرح است: Memory size exceeded.

$db_records_in_array_format; //This is a big array holding 1000 rows from a table each having 20 columns , every row is atleast 100 bytes , so total 1000 * 20 * 100 = 2MB  $cc = $db_records_in_array_format; //2MB more  some_function($cc); //Another 2MB ?  

خطای فوق زمانی رخ می دهد که توسعه دهنده بخواهد یک فایل csv وارد (import) کند یا یک جدول را به صورت فایل csv خروجی (export) دهد.

کدنویسی به روش های فوق سبب می شود اسکریپت اپلیکیشن مکررا به علت کمبود حافظه با خرابی مواجه شود. در واقع استفاده از روش فوق، زمانی که متغیرها حامل مقادیر کم حجم هستند، مشکلی را به وجود نمی آورد اما برای مدیریت متغیرهای حجیم این روش دیگر کارا محسوب نمی شود.

توصیه می شود برای ارسال مقادیر سنگین، مقدار حقیقی متغیر و نه کپی از آن را ارسال کرده (تکنیک pass by reference) و یا آن مقدار را داخل متغیرهای کلاس (class variable) ذخیره نمایید:

$a = get_large_array();  pass_to_function(&$a);  

با پیاده سازی این تکنیک، عین متغیر (نه صرفا کپی از مقدار آن) در اختیار تابع قرار می گیرد.

class A  {      function first()      {          $this->a = get_large_array();          $this->pass_to_function();      }      function pass_to_function()      {          //process $this->a      }  }  

حال اگر آن ها را بلافاصله unset نمایید، حافظه آزاد شده و اسکریپت می تواند بدون اخلال به اجرا ادامه دهد. در زیر مثال ساده ای را مشاهده می کنید که در آن روش ارسال عین مقدار (assign by reference) می تواند از هدر رفت حافظه جلوگیری نماید.

';  $b = $a;  $b[0] = 'B';  echo 'Memory usage in MB after 1st copy : '. memory_get_usage() / 1000000 . '
'; $c = $a; $c[0] = 'B'; echo 'Memory usage in MB after 2st copy : '. memory_get_usage() / 1000000 . '
'; $d =& $a; $d[0] = 'B'; echo 'Memory usage in MB after 3st copy (reference) : '. memory_get_usage() / 1000000 . '
'; خروجی قطعه کد بالا در یک دستگاهی که php 5.4 را اجرا می کند، به صورت زیر می باشد: Memory usage in MB : 18.08208 Memory usage in MB after 1st copy : 27.930944 Memory usage in MB after 2st copy : 37.779808 Memory usage in MB after 3st copy (reference) : 37.779864

همان طور که مشاهده می کنید در مثال سوم (کپی سوم) که عین مقدار ارسال شده (pass by reference)، میزان مصرف حافظه به حداقل رسیده است. در کپی های دیگر میزان حافظه ی مورد نیاز کاهش نیافته است.

25. کد اتصال به دیتابیس را به یک نمونه در کل اسکریپت خود محدود نمایید:

سعی کنید در کل اسکریپت پروژه ی خود تنها یک نمونه از کد اتصال به دیتابیس داشته باشید. بدین ترتیب که در ابتدای پروژه یک connection به دیتابیس باز کرده و آن را تا پایان استفاده نمایید و سپس همین اتصال را در انتهای اسکریپت ببندید. داخل توابع خود به دیتابیس کد اتصال قرار ندهید. نمونه ی زیر به هیچ وجه توصیه نمی شود:

function add_to_cart()  {      $db = new Database();      $db->query("INSERT INTO cart .....");  }  function empty_cart()  {      $db = new Database();      $db->query("DELETE FROM cart .....");  }  

زمانی که توسعه دهنده در اسکریپت خود چندین نمونه کد اتصال به دیتابیس تعریف می کند، هر بار مفسر با این کد مواجه می شود باید یک نمونه از آن در حافظه ایجاد کرده و در نتیجه علاوه بر اشغال حافظه بی مورد ، سرعت را اجرا پایین بیاورد.

لازم است برای database connection و تنظیم کد اتصال به دیتابیس، الگو توسعه ی singleton را پیاده سازی نمایید.

26. برای انجام عملیات بر روی دیتابیس، از نوشتن کوئری خالص و مسقیم SQL خودداری نمایید. این دستورات را داخل توابع php تعریف کرده و سپس آن ها را فراخوانی کنید:

$query = "INSERT INTO users(name , email , address , phone) VALUES('$name' , '$email' , '$address' , '$phone')";  $db->query($query); //call to mysqli_query()  

اگر چه روش بالا آسان ترین راه برای نوشتن کوئری های SQL، تعامل با دیتابیس و انجام عملیاتی نظیر INSERT، UPDATE و DELETE بر روی جداول آن می باشد، اما کاستی های هم دارد که در زیر به تفصیل شرح خواهیم داد:

  • تمامی مقادیر را باید هر بار به صورت دستی escape (آن ها را به منظور امنیت و جلوگیری از حمله ی SQL injection ایمن سازی نمایید و کاراکترهایی معنای خاصی برای sql دارند را فیلتر کنید) نمایید.
  • هر بار ساختار دستور کوئری را به صورت دستی از نظر صحت و درستی syntax بررسی نمایید.
  • در این روش ممکن است کوئری های ناصحیح برای طولانی مدت نادیده گرفته شوند (مگر اینکه هر بار آن را ها چک کنید).
  • و در نهایت تعمیم و نگهداشت کوئری های طولانی مانند نمونه ی فوق، می تواند دشوار باشد.

راه حلی که ما برای بهینه سازی تعامل با دیتابیس توصیه می کنیم، استفاده از الگو توسعه ی ActiveRecord می باشد.

در این روش توسعه دهنده تعدادی تابع ساده می نویسد، کوئری ها را مانند نمونه ی زیر از تابع فراخوانی می کند. در واقع تابعی می نویسید که کوئری های sql را آماده در اختیار شما قرار می دهد.

یک مثال ساده از فراخوانی تابع insert به روش activerecord مانند زیر می باشد:

function insert_record($table_name , $data)  {      foreach($data as $key => $value)      {      //mysqli_real_escape_string          $data[$key] = $db->mres($value);      }      $fields = implode(',' , array_keys($data));      $values = "'" . implode("','" , array_values($data)) . "'";      //Final query         $query = "INSERT INTO {$table}($fields) VALUES($values)";      return $db->query($query);  }   //data to be inserted in database  $data = array('name' => $name , 'email' => $email  , 'address' => $address , 'phone' => $phone);  //perform the INSERT query  insert_record('users' , $data);  

همان طور که در مثال بالا مشاهده می کنید، می توان داده ها را بدون نیاز به استفاده از دستور INSERT در دیتابیس درج کرد. تابع insert_record خود داده ها را escape می کند.همچنین یکی از مزایای بسیار بزرگ استفاده از روش فوق، این است که چون داده ها در قالب یک آرایه ی php قرار داده می شوند، هر گونه خطای دستوری (syntax error) بلافاصله توسط مفسر php شناسایی می شود.

این تابع می تواند داخل یک کلاس دیتابیس تعریف شده و به راحتی همچون $db->insert_record() فراخوانی شود. می توان به همین شیوه برای عملیات update، select، delete نیز یک تابع تعریف کرد.

27. محتوا و خروجی دیتابیس را داخل فایل های static قرار دهید:

می توان صفحاتی که خروجی عملیات دیتابیس همچون واکشی داده ها در آن ها قرار می گیرند، مانند فایل های cms، را در حافظه ی نهان به طور موقت ذخیره کرد (cache). بدین معنی که زمانی که داده ها تولید شدند، می توانید یک کپی از آن ها داخل فایل ذخیره کرد. حال زمانی که همین صفحه درخواست می شود، می توانید آن را از پوشه ی cache واکشی نمایید و دیگر لازم نیست که اطلاعات را مجددا از دیتابیس درخواست (query بگیرید) کنید.

مزایای این روش به شرح زیر می باشد:

  • با این کار php دیگر نیازی ندارد عملیات تکراری (تولید صفحه) را انجام دهد و از این جهت سرعت اپلیکیشن و پاسخ دهی افزایش می یابد.
  • هر چه تعداد کوئری هایی که بر روی دیتابیس اجرا می شود، کاهش یابد، دیتابیس mysql نیز کمتر درگیر بارگذاری داده ها می شود.

28. داده های session را داخل دیتابیس ذخیره نمایید:

متغیرهای session مقیم در فایل (file-based session) محدودیت های زیادی دارند. اپلیکیشن هایی که از این session ها استفاده می کنند، قادر به مدیریت چندین سرور نیستند و نمی توانند متناسب با چندین سرور بزرگ شوند (scale) چراکه داده ها در یک سرویس دهنده ذخیره می گردد. اما اگر داده های session را داخل دیتابیس ذخیره نمایید، در آن صورت می توانید به راحتی از چندین سرور به دیتابیس دسترسی داشته باشید. علاوه بر این زمانی که یک سرور میزبان چندین اپلیکیشن می باشد (shared hosting)، فایل های session داخل پوشه ی tmp ذخیره می شوند که سایر حساب های کاربری نیز به آن دسترسی دارند. این امر امنیت اپلیکیشن را به خطر می اندازد.

ذخیره سازی داده های session در دیتابیس، بسیاری از عملیات دیگر را آسان می سازد:

  • دیگر نام کاربری یکسان (username) قادر نخواهد بود به طور همزمان به سایت وارد شود. به بیان دیگر، نام کاربری یکسان اجازه نخواهند داشت از دو سرویس گیرنده ی متفاوت همزمان به سرور لاگین کنند.
  • وضعیت کاربران فعال در سایت را بهتر دنبال کرده و بررسی نمایید.

29. از متغیرهای سراسری (global ها) استفاده نکنید:

  • از دستور define استفاده نمایید/ثوابت تعریف کرده و بجای متغیرهای سراسری از آن ها استفاده کنید.
  • با استفاده از تابع مقادیر را بازیابی نمایید.
  • از Class استفاده کنید و با استفاده از کلیدواژه ی $this اعضای کلاس را فراخوانی نمایید.

30. آدرس سایت خود را داخل تگ base در بخش head صفحه html قرار دهید:

یک مثال ساده:

                                                              

با استفاده از این تگ شما می توانید یک نشانی یا آدرس پایه برای کلیک پیوندهای (لینک) موجود در صفحه تعیین کنید. تگ base می تواند نقش url اصلی ‘ROOT’ را برای تمامی url های نسبی (relative) در بدنه ی صفحه ی html (تگ body) ایفا کند.

المان مذکور به خصوص زمانی بکار می آید که فایل های static (حاوی عکس و متن و کدخای جاوا اسکریپت و css و غیره ..) داخل پوشه و زیرپوشه هایی سازمان دهی شده باشند.

مثال:

www.domain.com/store/home.php
www.domain.com/store/products/ipad.php

در فایل home.php می توان کد html زیر را نوشت:

 Home   Ipad  

اما در فایل ipad.php، لینک ها می بایست به صورت زیر نوشته شده باشند:

Home  Ipad  

دلیل آدرس دهی فوق این است که فایل ها در پوشه های مختلف قرار دارند. برای این منظور لازم است چندین نسخه از کد html جهت پیمایش (nav) تعبیه نمایید. با توجه به توضیحات یاد شده تنها راه حل سریع و کاربردی استفاده از تگ base می باشد.

         Home  Ipad      

نمونه ی فوق در پوشه ی home و product به طور یکسان عمل می کند. مقدار خصیصه ی href در تگ base برای ساخت url کامل به فایل home.php و products/ipad.php مورد استفاده قرار می گیرد.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *