Частина перша – 7 "дитячих" помилок, Захист додатків і безпеку, PHP, статті

Цільова аудиторія


Ця серія статей призначена для тих програмістів на мові PHP, які
хочуть уникнути найбільш загальних помилок у написанні коду. Читач, як мінімум,
повинен знати загальний синтаксис PHP, а також дуже бажаний деякий досвід
використання мови на практиці.


Введення


Одна з найбільш сильних сторін PHP є, одночасно, і його слабкою
стороною: PHP дуже простий у вивченні. Це приваблює багатьох людей, а проте,
незважаючи на його уявну простоту, не так-то просто навчитися використовувати цей
мову правильно і ефективно.


Як правило, справа в недостатній практиці програмування. Недосвідчені
програмісти стають перед особою необхідності створення складних
веб-додатків. Тому часто-густо допускаються помилки, яких уникнув би
досвідчений програміст, такі як необгрунтоване використання функції printf () або
неправильне використання семантики PHP.


У цій серії з трьох статей представлені найбільш, на нашу думку,
характерні помилки. Ці помилки можна класифікувати по декількох категоріях,
від <некритичних> до <смертельних>. Поряд з аналізом цих помилок,
представлені способи їх уникнення, а також деякі <маленькі хитрощі »,
накопичені за багато років практики програмування.


Частина 1: Описуються 7 <дитячих> помилок (№ 21-15, у зворотному
порядку, відповідно до ступеня серйозності по нашій класифікації). Такі
помилки не викликають серйозних проблем, але призводять до зменшення ефективності
роботи програми, а також висловлюються в громіздкому мають важко коді, в
який, до того ж, важко вносити зміни.


Частина 2: Наступні 7 помилок (№ 14-8) відносяться до <серйозним>.
Вони ведуть до ще більш значного зменшення швидкості виконання коду,
зменшення безпеки скриптів; код стає ще більш заплутаним.


Частина 3: Опис семи, останніх, <смертельних> помилок. Ці
помилки концептуальні за своєю природою і є причиною появи помилок,
описаних у 1-ій і 2-ий частинах статті. Вони включають і такі помилки, як
недостатнє уваги, приділений як проекту в цілому, так і коду програми, в
зокрема.


21. Невиправдане використання функції printf ()


Функція printf() призначена для виведення форматованих
даних.


Наприклад, її слід використовувати при необхідності виведення змінної в
форматі з плаваючою комою з певною точністю, або в будь-якому іншому
випадку, коли виникає необхідність зміни формату виведених даних.


Нижче наведено приклад обгрунтованого застосування функції printf().
В даному випадку вона використовується для форматованого виведення числа
<Пі>:

<?php

printf ("Число Пі:% 2f
<br>
", M_PI);
printf ("Це теж число Пі:% 3f
<br>
", M_PI;
printf ("І це Пі:% 4f
<br>
", M_PI);

?>


Примітка: Спостерігаються випадки патологічної боязні функції
printf(), Коли люди пишуть свої функції форматованого виводу,
деколи по 30-40 рядків, хоча всі проблеми міг би вирішити один-єдиний виклик
функції printf().

Багато програмістів використовують функцію printf() для виведення
змінних, результатів виконання функцій, а іноді навіть звичайних текстових даних.
Найбільш часто це відбувається в наступних двох випадках:



Коли слід використовувати print()


Виклик функції printf() найчастіше використовується там, де слід
б використовувати print(). У наступному прикладі функція
printf() використовується для виведення чотирьох змінних:

<?php

$name = “Sterling Hughes”;
$job = “Senior Engineer”;
$company = “DesignMultimedia”;
$email = “shughes@designmultimedia.com”;

printf ( "Мене звуть% s
<br>

Я працюю% s,% s
<br>

Моя адреса E-mail:% s
<br>
",
$name, $job, $company, $email );
?>


В даному випадку можливо (і бажано!) Застосування print():

  print "Мене звуть $ name
<br>

Я працюю в $ company, $ job
<br>

Моя адреса E-mail: $ email
<br>
";


Використання print() замість printf() у випадках,
коли виводяться неформатований дані, як в даному прикладі, дає
наступні вигоди:



Використання функції printf() для виведення значення,
повертається функцією


Ще одна характерна помилка використання функції printf()
висновок значення, що повертається функцією, як в наступному прикладі:

<?php

printf ("Знайдено% d входжень рядка% s", count ($result), $search_term);

?>


Поряд з функцією print(), При використанні її в тих же цілях,
слід використовувати оператор "."В даному випадку цей оператор
додає текст до результату виклику функції:

<?php

print "Знайдено" .
count ($result) .
"Входжень рядка $ search_term";

?>


Використання оператора . в парі з функцією print()
дозволяє уникнути використання більш повільної функції
printf().


20. Неправильне застосування семантики мови


Багато програмістів використовують у своїй роботі PHP, фактично не розуміючи
тонкощів цієї мови. Одна з тонкощів – різниця між синтаксисом і
семантикою PHP.



Зауважте: <слід>. У мовах з чітким поділом типів (таких як
Java або C) немає поняття "слід> (в загальному випадку, хоча бувають і
винятки). У такому випадку компілятор змусить використовувати змінні
строго певного типу.


Мови, в яких відсутній саме визначення типів змінних, надають
більше гнучкості в написанні коду. Але, як би там не було, в разі неправильного
використання семантики для більшості функцій PHP слід очікувати появи
повідомлення про помилку.


Візьмемо шматок коду, який відкриває файл і виводить його порядково:

<?php

$fp = @fopen ( “somefile.txt”, “r” )
or die ( "Не можу відкрити файл somefile.txt" );

while ($line = @fgets ( "$fp", 1024)) / / Тут помилка!
{
print $line;
}

@fclose ("$fp") / / І тут теж color
or die( "Не можу закрити файл somefile.txt" );

?>


У даному випадку з'явиться повідомлення про помилку типу:
“Warning:
Supplied argument is not a valid File-Handle resource in tst.php on line
4”
("Увага: аргумент не може бути дескриптором файлу")


Це викликано тим, що змінна $fp укладена в подвійні лапки,
що однозначно визначає її як рядок, тоді як функція fopen()
очікує в якості першого аргументу дескриптор, але НЕ рядок.
Відповідно, вам слід використовувати змінну, яка може
містити дескриптор.


Примітка: У даному випадку, рядковий тип допустимо синтаксично.


Для вирішення проблеми слід просто прибрати подвійні лапки:

<?php
$fp = @fopen ( “somefile.txt”, “r” )
or die ( "Не можу відкрити файл somefile.txt" );

while ( $line = @fgets ($fp, 1024) )
{
print $line;
}

@fclose ($fp)
  or die ( "Не можу закрити файл somefile.txt" );
?>


Як уникнути неправильного застосування семантики?


У наведеному прикладі генерується повідомлення про помилку. Але PHP надає
програмісту більше свободи, ніж інші, традиційні мови програмування.
Це дозволяє отримувати цікаві результати. Як мінімум, теоретично
можливо написати коректний код, неправильно використовуючи семантику мови.


Але будьте обережні, заграючи з семантикою мови! Можлива поява
важковловимий помилок в програмах. Якщо ж ви все-таки вирішили
поекспериментувати, вам слід розуміти три ключові моменти:



  • Типи: У PHP кожна мінлива в будь-який момент часу відноситься до
    певному типу. І це незважаючи на той факт, що її тип можна вільно
    змінювати. Іншими словами, у мові PHP змінна не може існувати, при
    цьому не ставлячись до певного типу (і, відповідно, не володіючи
    характеристиками, властивих цьому типу). У PHP є 7 основних типів змінних:
    Boolean, resource, integer,
    double, string, array і
    object.
  • Область видимості: У PHP змінні мають область видимості, яка
    визначає те, звідки вона може бути доступна, і наскільки довго буде
    існувати. Непорозуміння концепції <області видимості> може
    виявлятися у вигляді різного роду <плаваючих> помилок.
  • php.ini: При написанні коду слід розуміти, що не всі користувачі
    мають таку ж конфігурацію програмно-апаратних засобів, як і ви. Таким
    чином, абсолютно необхідно зайвий раз переконатися, чи зберігається
    працездатність вашого коду в тій конфігурації, в якій програма повинна
    працювати, а не в тій, в якій розроблялася.

19. Недостатньо або надмірно коментований текст


Погано документований текст програми є ознакою егоїстичного
програміста. Результатом спроби аналізу вашої програми з метою внесення
поліпшень буде тільки головний біль. Причому всі програмісти вважають
самодокументірованний код хорошим тоном, але самі вкрай рідко пишуть
коментарі.


Слід також уникати надмірних коментарів. Це теж зустрічається дуже
рідко, і, знову ж таки, створює важко читається вихідний код. Наступний приклад це
ілюструє:

<?php / / Початок коду

$age = 18; / / Вік дорівнює 18
$age++; / / Збільшимо $ age на один рік

/ / Надрукуємо привітання
print "Вам зараз 19 років, і це означає, що Вам вже було:";
print "
<br>
<br>
";

/ / Цикл "для" щоб вивести всі
/ / Попередні значення віку
for ($idx = 0; $idx < $age; $idx++)
{
/ / Надрукуємо кожне значення віку
print "$ Idx років
<br>
";
}
/ / Кінець коду
?>


І все-таки: де золота середина?


Отже, який же обсяг коментарів слід поміщати в скрипт?! Це залежить від
багато чого: від часу, яким ви володієте, від політики компанії, складності
проекту і т.д. Тим не менш, запам'ятайте кілька основних принципів, яким
треба дотримуватися при написанні програм незалежно від вашого рішення:



  • Перед тілом функції завжди розміщуйте коментар – призначення функції.
  • Додавайте коментарі в сумнівних ділянках коду, коли немає впевненості,
    що він буде працювати як треба.
  • Якщо призначення коду неочевидно, внесіть інформацію про призначення цього
    ділянки. Ви ж потім скористаєтеся цим коментарем.
  • Уникайте коментарі виду # – Використовуйте лише /*
    */
    або //.

Наступний приклад ілюструє гарний стиль коментарів:

<?php
// Random_Numbers.lib
/ / Генерація випадкових чисел різного типу

mt_srand((double)microtime()*1000000);

//
// mixed random_element(array $elements[, array weights])
/ / Повертає випадковий елемент масиву-аргументу
/ / Масив weights містить відносні ймовірності
/ / Вибірки елементів
//

function random_element ($elements, $weights = array())
{

/ / Для коректного функціонування цього алгоритму
/ / Кількість елементів масиву має бути рівним
/ / Кількістю елементів масиву відносних ймовірностей

if (count ($weights) == count ($elements)) {
foreach ($elements as $element) {
foreach ($weights as $idx) {

/ / Примітка: ми не використовуємо $ idx, тому що
/ / Нам не потрібен доступ до окремих елементів
/ / Масиву weights

$randomAr[] = $element;
}
}
}
else {
$randomAr = $elements;
}

$random_element = mt_rand (0, count ($randomAr) – 1);
return $randomAr [$random_element];
}
?>


18. Занадто багато змінних – надто великий час
виконання


Деякі прямо-таки страждають нав'язливою ідеєю вводити тимчасові змінні
де треба і де не треба. Абсолютно неможливо зрозуміти, чим керувався
людина, яка написала такий код:


<?php
$tmp = date ("F d, h:i a"); / / Тобто формат дати February 23, 2:30 pm
print $tmp;
?>


Для чого тут використана тимчасова мінлива?! Вона просто не потрібна:


<?php
print date ("F d, h:i a");
?>


На жаль, багато програмісти ніяк не можуть позбутися цієї поганої
звички. Використання тимчасових змінних уповільнює виконання програми. Для
збільшення швидкості коду, де це можливо, краще скористатися вкладенням
функцій. Використання тимчасових змінних часто збільшують час
виконання скриптів майже на чверть.


Ще одна причина, по якій слід уникати використання зайвого
кількості тимчасових змінних, це погіршення читання коду. Порівняйте два
наведених прикладу. Який з них виглядає більш елегантно – з використанням
тимчасової змінної чи без? Який код простіше прочитати? Використання зайвих
тимчасових змінних веде до написання менш читається і ясного коду.


Плюси використання тимчасових змінних


Введення тимчасових змінних дозволяє спростити деякі складні вирази
або виклики функцій. Ще вони приносять користь, коли дозволяють уникнути
багаторазового виклику функції з одними і тими ж аргументами.


Ось приклад, в якому не використовується зайвих змінних:

<?php

// string reverse_characters (string str)
/ / Перевертає рядок символів

function  reverse_characters ($str)
{
return implode ("", array_reverse (preg_split ("//", $str)));
}

?>


Викликом функції implode() в якості одного з параметрів
передається результат виконання вкладених функцій, тому такий код важко
прочитати. В даному випадку нам може здорово допомогти використання тимчасової
змінної:

<?php

// string reverse_characters (string str)
/ / Перевертає рядок символів

function reverse_characters ($str)
{
$characters = preg_split ("//", $str);
    $characters = array_reverse ($characters);
    return implode ("",  $characters);
}

?>


Золоте правило


Якщо ви думаєте, ввести чи ні ще одну тимчасову змінну, задайте собі
два питання:



  • Чи буде ця змінна використана хоча б двічі?
  • Значно Чи покращиться з її введенням читаність коду?

Якщо на будь-який з цих питань ви відповіли <та>, тоді введіть
тимчасову змінну. Інакше комбінуйте виклики функцій (якщо це необхідно) і
обійдіться без її використання.


17. Переписуємо стандартні функції


Дехто рекомендує перейменовувати стандартні функції для того, щоб
програмістам на Visual Basic "е простіше було перейти до використання мови
PHP:

<?php
function len ($str) {
return strlen ($str);
}
?>

Зустрічаються також рекомендації, приступаючи до програмування на PHP, першим
справою замінювати імена вбудованих функцій більш звичними.


Існує, як мінімум, дві причини цього не робити. По-перше і перш
за все, ми отримуємо менше читають код. Люди, які читають ваш код, побачать масу
очевидно непотрібних функцій і будуть сильно здивовані, чому ж вами не
використовувалися стандартні функції PHP.


Ну і, нарешті, це уповільнює програму. Справа не тільки в необхідності
обробки більшого об'єму коду, а й у тому, що для виклику такої
користувача функції, потрібно більше часу, ніж для прямого виклику
стандартної функції.


Використовуйте стандартні функцій мови!


Іноді так важко встояти! Адже програміст рідко знає відразу весь набір
функцій – у нього зазвичай немає часу запам'ятати їх все. Чому б просто не
перейменувати функцію? Але, повторимося, цього не слід робити в силу викладених
вище причин.


Добре б мати під рукою довідник по функціях PHP (зручно використовувати
індексовану версію в форматі PDF). І перед тим як написати будь-яку
функцію, уважно подивитися – не існує вона вже в списку стандартних
функцій.


Але слід зауважити, що в кодах програм можна зустріти користувача
функції, написані ще до їх впровадження як стандартних (наприклад,
функції порівняння двох масивів). Це не означає, що ви обов'язково повинні
переписати код і замінювати їх стандартними функціями.


16. Клієнтська частина програми не відокремлюється від серверної
частини


Багато програмістів рекомендують об'єднувати код HTML (інтерпретується на
стороні клієнта) та код PHP (що виконується сервером) в один великий файл.


Для маленьких сайтів це, можливо, непогано. Але, коли ваш сайт почне рости,
ви можете зіткнутися з проблемами при необхідності додати будь-які нові
функції. Такий стиль програмування призводить до дуже <неслухняному> та
громіздкому коду.


API функцій


Якщо ви зібралися відокремити код PHP від ​​HTML коду, у вас є два варіанти.
Один спосіб – створення функцій динамічного формування висновку і помістити їх
в потрібне місце на веб-сторінці.


Наприклад, так:

index.php – код сторінки

<?php include_once ("site.lib"); ?>
<html>
<head>
<title><?php print_header (); ?></title>
</head>
<body>
<h1><?php print_header (); ?></h1>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="25%">
<?php print_links (); ?>
</td>
<td>
<?php print_body (); ?>
</td>
</tr>
</table>
</body>
</html>

site.lib – Сам код програми

<?php

$dbh = mysql_connect ("localhost", "sh", "pass")
or die (sprintf ("Не можу відкрити з'єднання з MySQL [% s]:% s",
mysql_errno (), mysql_error ()));

@mysql_select_db ("MainSite")
  or die (sprintf ("Не можу вибрати базу даних [% s]:% s",
mysql_errno (), mysql_error ()));

$sth = @mysql_query ("SELECT * FROM site", $dbh)
or die (sprintf ("Не можу виконати запит [% s]:% s",
mysql_errno (), mysql_error ()));

$site_info = mysql_fetch_object ($sth);

function print_header ()
{
global $site_info;
print $site_info->header;
}

function print_body ()
{
global $site_info;
print nl2br ($site_info->body);
}

function print_links ()
{
global $site_info;

$links = explode ("
", $site_info->links);
$names = explode ("
", $site_info->link_names);

for ($i = 0; $i < count ($links); $i++)
{
print "
<a href="$links[$i]">$names[$i]</a>

<br>
";
}
}
?>


Очевидно, такий код краще читаємо. Ще одна перевага використання цієї
концепції – можливість зміни дизайну без модифікації самого коду
програми.


Плюси використання API функцій



  • Щодо чистий, ясний код
  • Швидкий код

Мінуси використання API функцій



  • Не настільки наочно як система шаблонів
  • Все-таки, для модифікації дизайну потрібно деяке знання PHP

Система шаблонів


Другий спосіб, який використовується для розділення PHP і HTML коду – використання
шаблонів. В даному випадку, деякі елементи дизайну замінюються
користувацькими тегами, а сама програма сканує файл на предмет їх наявності
і замінює їх необхідною інформацією.


Приклад використання шаблонів:


<html>

<head>
<title>%%PAGE_TITLE%%</title>
</head>

<body %%BODY_PROPERTIES%%>
<h1>%%PAGE_TITLE%%</h1>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="25%">%%PAGE_LINKS%%</td>
<td>%%PAGE_CONTENT%%</td>
</tr>
</table>
</body>

</html>


Потім пишемо програму, переглядали код шаблону і при виведенні заменяющую
теги виду %%:%% потрібною інформацією.


Примітка: непоганий клас для використання його в системі шаблонів –
FastTemplate, його можна завантажити lkx2@mail.ru Відразу хочеться
пояснити, що дослівний переклад не був самоціллю, але, тим не менш,
стиль і сенс оригінальної статті по можливості;)) зберігалися.
Всі зауваження та побажання вітаються і будуть враховані, бо готується переклад
другій частині цієї статті. Тільки прохання ногами не штовхати;)) Все ж я
сподіваюся, що якщо ви до цього місця дочитали, то не все так погано;))

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*