Форум программистов, компьютерный форум, киберфорум
Наши страницы

PHP для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 232, средняя оценка - 4.94
KOPOJI
Эксперт HTML/CSSЭксперт PHP
16702 / 6624 / 433
Регистрация: 12.06.2012
Сообщений: 19,879
Завершенные тесты: 1
#1

FAQ по распространенным ошибкам - PHP

07.09.2012, 16:05. Просмотров 34531. Ответов 8
Метки нет (Все метки)

Введение
Приветствую всех. Здесь будут выкладываться ответы на самые распространенные ошибки и проблемы, с которыми сталкиваются новички (а порой и не только новички) при программировании на PHP.

Содержание #
  1. Распространенные ошибки в PHP
  2. Отладка программы
  3. Работа с формами в PHP


Распространенные ошибки в PHP

Краткое вступление. Любой программист, рано или поздно, но сталкивается с ошибками. PHP несколько отличается от других, "стандартных" языков программирования. Отличия, конечно же, больше всего заметны в плане того, что во-первых, здесь нет жесткой типизации, а во-вторых - PHP язык с интерпретатором, а не компилятором.

Уровни отображения ошибок в PHP

В PHP существует несколько уровней ошибок. Вот таблица основных уровней
Уровень ошибкиТип диагностируемой ошибки
E_ERRORОшибки обычных функций (критичные ошибки)
E_WARNINGОбычные предупреждения (не критичные ошибки)
E_PARSEОшибки синтаксического анализатора
E_NOTICEЗамечания (аномалии в коде, возможные источники ошибок — следует отключить при наличии русского текста в коде, так как для интернациональных кодировок не обеспечивается корректная работа).
E_CORE_ERRORОшибки обработчика
E_CORE_WARNINGПредупреждения обработчика
E_COMPILE_ERRORОшибки компилятора
E_COMPILE_WARNINGПредупреждения компилятора
E_USER_ERRORОшибки пользователей
E_USER_WARNINGПредупреждения пользователей
E_USER_NOTICEУведомления пользователей
E_ALLВсе ошибки
Начиная с PHP5 появился еще один уровень - E_STRICT, который предупреждает об использовании устаревших функций, "дает советы" по способности взаимодействия и будущей совместимости кода.
Более подробно об этом можете посмотреть здесь и здесь
уровень отображения можно прописать непосредственно в коде, с помощью функции
PHP
1
error_reporting(LEVEL);
где вместо LEVEL пишем соответственно уровень (к примеру E_ALL). Также можно задавать и числовое значение - т.е.
PHP
1
error_reporting(0);
означает скрывать все ошибки.
По умолчанию в PHP стоит уровень отображения ошибок
Bash
1
E_ALL &~E_NOTICE
Это значит, что ошибки уровня E_NOTICE (необъявленные переменные, индексы массивов без апострофов/кавычек, и т.п.) не будут отображаться.
На мой взгляд, программист всегда должен знать обо всем, что творится у него в коде во время отладки программы, поэтому я всегда прописываю
PHP
1
2
ini_set('display_errors','On'); #включаем отображение ошибок если выключено
error_reporting(E_ALL | E_STRICT); #устанавливаем режим отображения - все ошибки и советы
Ну, с вводной частью покончили, перейдем, собственно, к самим ошибкам.

"Разбор полетов", или где ошибка?

PHP
1
<?php echo $text; ?>
Мы не объявили эту переменную, и при выводе (если включены ошибки E_NOTICE) мы получим это предупреждение:
Notice: Undefined variable: text in T:\home\localhost\www\proba\index.php on line 3
Разберем саму "структуру" ошибки
Notice: тип ошибки
Undefined variable: text сама ошибка
in T:\home\localhost\www\proba\index.php месторасположение ошибки
on line 3 на какой строке
То есть здесь у нас ошибка типа NOTICE о том, что не объявлена переменная $text по указанному адресу на 3 строке
Следовательно ее нужно инициализировать (просто присвоить какое то значение).
Идем далее.
PHP
1
2
3
4
<?php 
$text = 'text'
echo $text;
?>
Parse error: syntax error, unexpected T_ECHO in T:\home\localhost\www\proba\index.php on line 3
Эта ошибка в синтаксисе (syntax error) - дословно - не ожидается T_ECHO (т.е. оператор echo) на 3 строке.
Эта ошибка также возникнет в ситуации с кодом
PHP
1
2
3
<?php 
echo echo 'text'; #дважды echo - ошибка
?>
Если видите такую ошибку - нужно сразу смотреть, где вы что то не доставили (точка с запятой - как в примере, обычная или фигурная скобка)
В php любое выражение должно заканчиваться точкой с запятой. Позволительно опускать ее только в конце php-скрипта если после него не идет никаких других символов (в том числе и пустой строки).
Далее
PHP
1
2
3
4
<?php 
$text = 'text';.
echo $text;
?>
Parse error: syntax error, unexpected '.' in T:\home\localhost\www\proba\index.php on line 2
тут тоже все предельно ясно. Не ожидается точка на второй строке, она лишняя)
PHP
1
2
3
4
5
<?php 
$text = 'text';
if(true {
echo $text;
?>
Parse error: syntax error, unexpected '{' in T:\home\localhost\www\proba\index.php on line 3
скобку забыли закрыть после условия. По закрытию мы сразу же получим следующую ошибку:
Parse error: syntax error, unexpected $end in T:\home\localhost\www\proba\index.php on line 5
И вот эта ошибка самая "непонятная" - в плане того, где ее искать. Указывает она на неожиданный конец кода на последней (в примере на 5) строчке и означает только одно - где то забыли закрыть условие. Остается только искать. Хорошо в этом помогает notepad++ и другие редакторы, где подсвечивает (или находит) парную скобку.
PHP
1
2
3
4
5
6
<?php 
$text = 'text';
if(true) { }
echo $text;
else echo 'fds';
?>
Parse error: syntax error, unexpected T_ELSE in T:\home\localhost\www\proba\index.php on line 5
ELSE должен идти сразу после закрытия if ( и только после if ! ), без всяких других выводов переменных и т.п.

PHP
1
2
3
<?php 
eecho 'text';
?>
Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in T:\home\localhost\www\proba\index.php on line 2
Ошиблись в написании
PHP
1
2
3
4
<?php
$text = array('first'=>0,'second'=>1,'third'=>2);
echo $text[first];
?>
Notice: Use of undefined constant first - assumed 'first' in T:\home\localhost\www\proba\index.php on line 3
Дословно: использование необъявленной константы, подставлено 'first' - это к тому, что нечисловые индексы массивов нужно писать в строковых литералах (кавычки или апострофы)

Отладка программы и поиск ошибок

Итак, как же выявить ошибки.

Установка отображения ошибок

Первым делом, необходимо прописать то, что я уже писал выше - это эти две "волшебные" строчки:
PHP
1
2
ini_set('display_errors','On'); #включаем отображение ошибок если выключено
error_reporting(E_ALL | E_STRICT); #устанавливаем режим отображения - все ошибки и советы
Далее. если мы это не писали или написали, но ошибок нет, а код работает не так как нам надо, то проверяем переменные:
PHP
1
var_dump($var);#$var - имя переменной
и смотрим что у нас в них находится за значение - то, что нам нужно, или же, все-таки, нет?

Возвращаемые значения var_dump()

Итак, что может вывести у нас var_dump().

NULL - переменная не объявлена, ей присвоили NULL или удалили с помощью unset()
bool(false) - логический (булев) тип - ЛОЖЬ
bool(true) - логический (булев) тип - ИСТИНА
int(число) - целое число
float(число) - вещественное число с плавающей точкой (дробное) или целое, но больше int (например так float(1.1111111111111E+229) )
object(a)#1 (число свойств) {свойства (имя и значения, в виде ассоциативного массива) } - объект (экземпляр) класса
resource(число) of type (тип ресурса) - ресурс
string(число символов в строке) "сама строка" - строка (текст)
array(число ключей) { ключ=>свойство } - массив

Добавлено через 1 час 41 минуту

Работа с формами в PHP

Форма должна выглядеть примерно так
HTML5
1
2
3
4
<form method="POST" action="" enctype="">
<input type="text" name="first" />
<input type="submit" name="ok_go" value="GO!" />
</form>
Разбор элементов формы

Разберем построчно нашу форму:
<form .. > - начало формы
method="POST" - метод отправки данных. Возможны два метода передачи данных формы: метод GET и метод POST.
GET - весь текст формы (все передаваемые значения) отображаются в адресной строке браузера.
POST - все передаваемые значения передаются скрыто
action="" - путь к документу, где будут обрабатываться наши данные. если пустой, или отсутствует, или прописано что то типа
PHP
1
action="<?=$_SERVER['PHP_SELF'];?>"
- значит данные будут отправляться в этот же файл
enctype="" - способ кодирования данных формы при отправке на сервер. При отстутствии надобности в загрузке файлов не нужен
Далее.
<input type="text" - type - это тип текстового поля (их полно, перечислять не буду).
name="first" - имя поля. Именно этот индекс нужно будет подставлять при обработке данных в массив $_POST
value="GO!" - отображаемый текст
</form> - Закрывающий тег формы.

Обработка полученных данных формы в PHP

В PHP, как я уже говорил, есть возможность отправлять формы методом POST и методом GET. в первом случае все данные находятся в суперглобальном массиве $_POST, во втором - аналогичном массиве $_GET с индексами (ключами) в виде названий полей. Мы будем разбирать метод POST, по аналогии легко переделать на метод GET

Теперь, непосредственно, обработка этих данных в php. Комментарии буду писать прямо в коде
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php #начало php-кода. если включены short_open_tag в php.ini - можно писать <? без php
/**
*isset() - проверяет на наличие переменной/значения (равно NULL или нет)
*empty() - проверяет переменную на пустоту. Обращаю внимание, 0 - для нее тоже пустота!
**/
if(isset($_POST['ok_go'])) { #если нажата клавиша формы
$first_var = $_POST['first'];#присваиваем значение первого поля первой переменной
#Важный момент. все переменные, полученные от пользователя нужно проверять и очищать!
$first_var = trim($first_var); #убираем пробелы по краям, если они есть
if(empty($first_var)) echo 'Пусто!'; #если пустая, выводим Пусто!
else { #не пустая
echo 'Вы ввели: <b>', $first_var, '</b>';
# echo поддерживает и конкатенацию, и вывод нескольких выражений одновременно
# причем с выводом через запятую работает немного побыстрее, чем через конкатенацию (склеивание) строк
}
}
?>
если все это совместить, выглядеть это будет так:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form method="POST">
<input type="text" name="first" />
<input type="submit" name="ok_go" value="GO!" />
</form>
<?php 
if(isset($_POST['ok_go'])) { #если нажата клавиша формы
$first_var = $_POST['first'];#присваиваем значение первого поля переменной
$first_var = trim($first_var); #убираем пробелы по краям, если они есть
 if(empty($first_var)) echo 'Пусто!'; #если пустая, выводим Пусто!
 else { #не пустая
  echo 'Вы ввели: <b>', $first_var, '</b>';
 }
}
?>
Простая отправка письма через форму (без всяких премудростей)

HTML5
1
2
3
4
5
6
7
8
9
10
<form method="post">
Name: <br />
<input type="text" name="name" />
E-mail: <br />
<input type="email" name="email" />
Message: <br />
<textarea name="text"></textarea>
<br />
<input type="submit" value="Отправить" />
</form>
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
if( isset($_POST['name'],$_POST['email'],$_POST['text']) ) {
 $name = trim($_POST['name']);
 $email = trim($_POST['email']);
 $text = trim($_POST['text']);
  if(empty($name) || empty($email) || empty($text)) { //если что то не ввели
   echo 'Вы заполнили не все поля!';
  }
  else { //все поля заполнены, отправляем
   $mailto = 'адрес кому письмо отправлять';
   $subject = 'Тема письма';
//формируем текст сообщения
   $message  = 'Сообщение от пользователя <b>'.$name.'</b>';
   $message .= 'E-mail пользователя: <a href="mailto:' . $email . '">' . $email . '</a><br />';
   $message .= 'Текст сообщения:<br />' . $text;
//формируем заголовки (кодировку только, остальное сами добавите по желанию)
   $headers = 'Content-type: text/html; charset=utf-8';
//отправляем письмо
   $mail = mail($mailto, $subject, $message, $headers);
//проверяем отправку
    if(TRUE === $mail) echo 'Ваше сообщение успешно отправлено!';
    else echo 'Произошла ошибка при отправке сообщения.';
//проверку можно записать короче при помощи тернарного оператора, вот так:
//  echo (TRUE === $mail) ? 'Ваше сообщение успешно отправлено!' : 'Произошла ошибка при отправке сообщения.' ;
//тогда нужно будет раскомментировать строчку выше и закомментировать строчки выше с проверкой
  }
}
?>
25
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.09.2012, 16:05
Здравствуйте! Я подобрал для вас темы с ответами на вопрос FAQ по распространенным ошибкам (PHP):

Вопросы по "FAQ по распространенным ошибкам" - PHP
Вопрос по теме http://www.cyberforum.ru/php-beginners/thread648097.html#post3458211 Очень полезная статья! И согласен, Попов особо...

Чем определяется одинаковость урлов /page?FAQ и /page.php?FAQ - PHP
Подскажите, пожалуйста, какая опция php или настройка сервера позволяет не указывать .php в урлах? Просто раньше у меня на сайте работал...

FAQ - PHP
Не могу скачать документацию http://ua2.php.net/get/php_enhanced_ru.chm/from/a/mirror , не вижу зеркала, может у кого есть локально дайте...

Preg_replace() FAQ? - PHP
хз, какая то хрень и не пойму в чем дело. Может кто подскажет, как так то )) есть строка: $data = '&lt;a...

PHPStorm - навигация по ошибкам анализатора - Разработка ПО
Добрый день! В правом верхнем углу есть значок анализатора (см. вложение). В окне просто отображается информация о них. Вопрос в том,...

Справочник по ошибкам Post платы - Visual C++ БД
Здравствуйте необходимо создать справочник по ошибкам Post платы ,нашел только платный,кому не трудно выделите время

8
crautcher
2014 / 1985 / 175
Регистрация: 27.05.2011
Сообщений: 6,832
07.09.2012, 16:31 #2
продолжение о теме ошибок и отладке , сегодня хочу написать об исключениях (Exception)
исключения вызываются :
PHP
1
throw new Exception('текст исключения');
Как мы видим используется оператор new, это означает, что мы создаем объект класса Exception, который мы можем унаследовать и дописать.

После вызова исключения мы видим на экране :
Fatal error: Uncaught exception 'Exception' with message 'текст исключения'
in /var/www/test.php:2
Stack trace: #0 {main} thrown in /var/www/test.php on line 2
Эта ошибка означает, что у нас не пойманное (uncaught) исключение c текстом ошибки 'текст исключения'

дабы не допустить фатальной ошибки , исключения необходимо отлавливать таким образом :
PHP
1
2
3
4
5
6
7
8
9
try  
 {  
   /* код который может выдать ошибку и 
       в случае ошибки вызовет исключение */
 }  
 catch (Exception $e)  
 {  
   /* получаем объект исключений $е */ 
 }
к примеру , на практике нам нобходимо реазлизовать функцию которая вернет результат формулы a * b / c
PHP
1
2
3
4
 function Averange($a ,$b ,$c)
 {
  return $a + $b / $c ;
 }
мы знаем что деление на 0 вызовет ошибку , используя исключения мы может отловить ее следующим образом:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php 
 
 function Averange($a,$b ,$c)
 {
  if ($c == 0) 
   { throw new Exception('на 0 делить нельзя'); }
  return $a + $b / $c ;
 }
 
 
 try  
 {  
  echo Averange(1,2,0);
 }  
 catch (Exception $e)  
 {  
  #вызвали метод получения текста исключения
  echo $e -> getMessage();
 }
на экране :
на 0 делить нельзя
после чего скрипт продолжает работу.

Зачем я затронул эту тему , ведь можно было просто вернуть false ?
А как вы проверите к примеру сможет ли открыть адресс функция file_get_contetns() ?

что-бы обезопасить функции результат которых нельзя проверить не вызвав ошибку , нужно немного отойти от темы...

обработчик ошибок
php может перенаправлять ошибки сценария в обработчик юзера функцией set_error_handler () .
пример :
PHP
1
2
3
4
5
6
7
8
function myErrorHandler($nr, $text, $file, $line)
{
 echo 'some error , nr - ' , $nr ,
 ' \'' , $text , '\' </br> file : ' , 
 $file , ' , line :' , $line;
}
set_error_handler("myErrorHandler");
file_get_contents('wrong_url');
на экране :
some error , nr - 2 'file_get_contents(wrong_url) [function.file-get-contents]: failed to open stream: No such file or directory'
file : /var/www/test.php , line :9
вызываем в обработчике исключение :
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function myErrorHandler($severity, $message, $file, $line)
{
 throw new ErrorException('wrong url');
}
set_error_handler("myErrorHandler");
 
 try  
 {  
  file_get_contents('wrong_url');
 }  
 catch (Exception $e)  
 {  
  echo $e -> getMessage();
 }
на экране:
wrong url
12
crautcher
2014 / 1985 / 175
Регистрация: 27.05.2011
Сообщений: 6,832
17.09.2012, 12:31 #3
Не используйте относительные пути - определяйте корневой путь

Иногда можно встретить код похожий на :
PHP
1
include('../../lib/some_class.php');
Этот подход имеет много недостатков:
PHP ищет сперва текущий каталог , а затем отталкиваясь от текущего места положения ищет целевой каталог - слишком много поисков .
Если файл с таким кодом будет включен в другой файл , то текущее место нахождение может измениться и будет ошибка .

старайтесь создавать абсолютные пути:
PHP
1
2
define('ROOT' , '/var/www/project/');
include(ROOT . '/../../lib/some_class.php');
Теперь это абсолютный путь и он всегда будет постоянным. Корневая директория теоретически может меняться ,и нам тогда придется менять все пути. Нам помогут магические константы , такие как __FILE__ :
PHP
1
2
define('ROOT' , pathinfo( __FILE__ , PATHINFO_DIRNAME));
include(ROOT . '/../../lib/some_class.php');
Теперь перенося свой проект в разные директории абсольютный путь файла всегда будет верен.

Ваш сценарий может подключать в начале большой список различных файлов - какие-то библиотеки , классы :
PHP
1
2
3
4
include ROOT .'/lib/Database.php';
include ROOT .'/lib/Mail.php';
include ROOT .'/lib/Session.php';
...
Это довольно примитивный пример .Код должен быть более гибким. Написав вспомогательную функцию , подключать файлы будет легче. Давайте рассмотрим пример:
PHP
1
2
3
4
5
6
7
8
function load_lib( $name )
{
    require_once( ROOT . '/lib/' . $name . '.php' );
}
load_lib('Database');
load_lib('Mail');
load_lib('Session');
...
Если изменится папка файлов , не надо будет править во всех местах а только в функции. Немного дороботав :
PHP
1
2
3
4
5
6
7
8
function load_lib($name)
{
    $path = ROOT . '/lib/' . $name . '.php');    
    if( file_exists($path) )
    {
        include $path; 
    }
}
11
KOPOJI
Эксперт HTML/CSSЭксперт PHP
16702 / 6624 / 433
Регистрация: 12.06.2012
Сообщений: 19,879
Завершенные тесты: 1
17.09.2012, 13:08  [ТС] #4
Несколько слов об ошибках Попова.
В сети, среди web-программистов, хорошо известен некий Евгений Попов, автор серии видеоуроков, любимец новичков и противоположность для программистов со стажем..
Итак, начнем.
Вот код регистрации на его сайте.
Кликните здесь для просмотра всего текста
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
    if (isset($_POST['login'])) { $login = $_POST['login']; if ($login == '') { unset($login);} } //заносим введенный пользователем логин в переменную $login, если он пустой, то уничтожаем переменную
    if (isset($_POST['password'])) { $password=$_POST['password']; if ($password =='') { unset($password);} }
    //заносим введенный пользователем пароль в переменную $password, если он пустой, то уничтожаем переменную
 if (empty($login) or empty($password)) //если пользователь не ввел логин или пароль, то выдаем ошибку и останавливаем скрипт
    {
    exit ("Вы ввели не всю информацию, вернитесь назад и заполните все поля!");
    }
    //если логин и пароль введены,то обрабатываем их, чтобы теги и скрипты не работали, мало ли что люди могут ввести
    $login = stripslashes($login);
    $login = htmlspecialchars($login);
 $password = stripslashes($password);
    $password = htmlspecialchars($password);
 //удаляем лишние пробелы
    $login = trim($login);
    $password = trim($password);
 // подключаемся к базе
    include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь 
 // проверка на существование пользователя с таким же логином
    $result = mysql_query("SELECT id FROM users WHERE login='$login'",$db);
    $myrow = mysql_fetch_array($result);
    if (!empty($myrow['id'])) {
    exit ("Извините, введённый вами логин уже зарегистрирован. Введите другой логин.");
    }
 // если такого нет, то сохраняем данные
    $result2 = mysql_query ("INSERT INTO users (login,password) VALUES('$login','$password')");
    // Проверяем, есть ли ошибки
    if ($result2=='TRUE')
    {
    echo "Вы успешно зарегистрированы! Теперь вы можете зайти на сайт. <a href='index.php'>Главная страница</a>";
    }
 else {
    echo "Ошибка! Вы не зарегистрированы.";
    }
    ?>

Пойдем по порядку.
PHP
1
2
if (isset($_POST['login'])) { $login = $_POST['login']; if ($login == '') { unset($login);} } //заносим введенный пользователем логин в переменную $login, если он пустой, то уничтожаем переменную
    if (isset($_POST['password'])) { $password=$_POST['password']; if ($password =='') { unset($password);} }
Что здесь неправильно. Во-первых, сама форма записи. isset() поддерживает передачу нескольких переменных на проверку, так почему бы не сделать так? И вообще, весь код необходимо заключать в проверку нажатия клавиши формы (или проверять метод отправки формы)
т.е. вот так
PHP
1
2
3
if(isset($_POST['кнопка_формы'])) {
#здесь код
}
либо
PHP
1
2
3
if($_SERVER['REQUEST_METHOD'] == 'POST') {
#здесь код
}
Вообще, если не использовали никакие подмены или что еще - то этого вполне хватает.
При необходимости, можно проверять существование нужных данных, но не таким способом. Как я уже говорил, в isset можно передавать несколько аргументов. Давайте посмотрим, как это можно делать.
PHP
1
2
3
4
5
6
7
if(isset($_POST['кнопка_формы'])) {
if(isset($_POST['login'],$_POST['password'])) {
#все данные существуют, можно работать
}
else 
   echo 'Вы заполнили не все данные';
}
Идем далее.
присваиваем переменные, попутно сразу очищая их от пробелов (можно и другие очистки сразу добавить - нечего расписывать код на десять строк вместо одной)
PHP
1
2
$login = trim($_POST['login']);
$password = trim($_POST['password']);
И уже только после того, как мы очистили от пробелов переменные, можно проверять на пустоту! Так как если не очистить, то обычный пробел в поле ввода спокойно пройдет эту проверку Попова. Теперь же проверим, пустая она или нет.
PHP
1
2
if(empty($login) || empty($password))
    echo 'Вы заполнили не все поля!';
Немного не в тему. Если у вас в теле цикла только одно действие - то не нужно заключать его в фигурные скобки. Тем более не нужно это делать в одну строку, это просто-напросто нечитабельно. Подумайте о себе и других в дальнейшем, форматируйте код так, чтобы было легко его читать.
Итак, совместив все это у нас получается такая запись:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if(isset($_POST['кнопка_формы'])) {
 
    if(isset($_POST['login'],$_POST['password'])) {
 
        #все данные существуют, можно работать
        $login = trim($_POST['login']);
        $password = trim($_POST['password']);
 
        #проверяем на пустоту
        if(empty($login) || empty($password))
            echo 'Вы заполнили не все поля!';
        else { #поля не пустые, идем дальше
            #здесь еще что то делаем
        }
 
    }
    else 
       echo 'Вы заполнили не все данные';
 
}
уже получше, проверяем дальше.
В php есть такая вещь как так называемые "магические (волшебные) кавычки". Они добавляют экранирование к ряду символов в отправляемые данные. Но, т.к. мы будем использовать mysql_real_escape_string() перед запросом, то нам нужно очистить от этих слэшей. В принципе, при авторизации можно убирать слэши по любому, если они не должны быть в логине или пароли (а обычно это так).
Проверить, включены кавычки или нет можно с помощью функции get_magic_quotes_gpc(). Я проверять не буду, а просто сразу очищу
PHP
1
2
$login = stripslashes($login);
$password = stripslashes($password);
Далее, необходимо подключиться к БД - т.е. подключить файл с подключением к БД
PHP
1
require_once './db.php'; #используйте путь от корневой директории, а не просто так пишите
Проверка наличия пользователя:

Код Попова.
PHP
1
2
$result = mysql_query("SELECT id FROM users WHERE login='$login'",$db);
    $myrow = mysql_fetch_array($result);
Неверно. По двум причинам. Во-первых, зачем что то извлекать, если можно просто подсчитать число таких пользователей. Во-вторых, данные не проэкранированы и подвержены к SQL-инъекциям. Исправим это.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
#экранирование
$login = mysql_real_escape_string($login);
$password = mysql_real_escape_string($password);
#выполняем сам запрос
$result = mysql_query('SELECT COUNT(1) FROM `users` WHERE `login`="'.$login.'"');
if($result)
    $data = mysql_fetch_array($result,MYSQL_NUM);
if(!empty($data[0]))
    echo 'Пользователь с таким логином уже существует!';
else {
#пользователь не найден, регистрируем
}
Далее
PHP
1
2
3
$result2 = mysql_query ("INSERT INTO users (login,password) VALUES('$login','$password')");
    // Проверяем, есть ли ошибки
    if ($result2=='TRUE')
С запросом вроде все нормально.. но вот с проверкой. Запомните, функции возвращают логический (булев) тип, а не строку! Так работает только по причине того, что php не жестко типизированный язык, в отличии от большинства, но это плохой код.
Правильно делать так:
PHP
1
2
3
4
5
6
7
if(TRUE === $result2) //только для запросов, которые НЕ возвращают ресурс, а только FALSE/TRUE
# или так
if(TRUE == $result)
#ну или и так можно
if($result)
#но никак не вот так
if($result == 'TRUE')
Ну и далее, опять ошибка читабельности - заключение одного условия в фигурные скобки
PHP
1
2
3
4
5
6
7
if ($result2=='TRUE')
    {
    echo "Вы успешно зарегистрированы! Теперь вы можете зайти на сайт. <a href='index.php'>Главная страница</a>";
    }
 else {
    echo "Ошибка! Вы не зарегистрированы.";
    }
Итак, перепишем код и посмотрим на то, что же у нас получилось.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
if(isset($_POST['кнопка_формы'])) {
 
    if(isset($_POST['login'],$_POST['password'])) {
 
        #все данные существуют, можно работать
        $login = stripslashes(trim($_POST['login']));
        $password = stripslashes(trim($_POST['password']));
 
        #проверяем на пустоту
        if(empty($login) || empty($password))
            echo 'Вы заполнили не все поля!';
        else { #поля не пустые, идем дальше
 
            #экранируем переменные для запроса
            $login = mysql_real_escape_string($login);
            $password = mysql_real_escape_string($password);
            
            #выполняем сам запрос
            $result = mysql_query('SELECT COUNT(1) FROM `users` WHERE `login`="'.$login.'"');
            
            if(TRUE == $result)
                $data = mysql_fetch_array($result,MYSQL_NUM);
 
            if(!empty($data[0]))
                echo 'Пользователь с таким логином уже существует!';
            else {
                #пользователь не найден, регистрируем
                $result2 = mysql_query ('INSERT INTO `users` (`login`,`password`) VALUES("'.$login.'","'.$password.'")');
                
            // Проверяем, есть ли ошибки
                if (-1 != mysql_affected_rows())
                    echo 'Вы успешно зарегистрированы! Теперь вы можете зайти на сайт.<br />
                    <a href="./">Главная страница</a>';
                else 
                    echo 'Произошла ошибка при регистрации. Пожалуйста, попробуйте позднее.';
            }
 
        }
 
    }
    else 
       echo 'Вы заполнили не все данные';
 
}
Ну и, конечно, можно его немного сократить еще:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
if(isset($_POST['кнопка_формы'])) {
 
    if( isset($_POST['login'], $_POST['password']) ) {
 
        #все данные существуют, можно работать
        $login = mysql_real_escape_string(stripslashes(trim($_POST['login'])));
        $password = mysql_real_escape_string(stripslashes(trim($_POST['password'])));
 
        #проверяем на пустоту
        if(empty($login) || empty($password))
            echo 'Вы заполнили не все поля!';
        else { #поля не пустые, идем дальше
            
            #выполняем сам запрос
            $result = mysql_query('SELECT COUNT(1) FROM `users` WHERE `login`="'.$login.'"');
            
            if($result)
                $data = mysql_fetch_array($result,MYSQL_NUM);
 
            if(!empty($data[0]))
                echo 'Пользователь с таким логином уже существует!';
            else {
                #пользователь не найден, регистрируем
                $result2 = mysql_query ('INSERT INTO `users` (`login`,`password`) VALUES("'.$login.'","'.$password.'")');
                
            // Проверяем, есть ли ошибки
                echo -1 !== mysql_affected_rows()
                    ? 'Вы успешно зарегистрированы! Теперь вы можете зайти на сайт.<br />
                    <a href="./">Главная страница</a>'
                    : 'Произошла ошибка при регистрации. Пожалуйста, попробуйте позднее.';
            }
        }
    }
    else 
       echo 'Вы заполнили не все данные';
}
А если убрать все комментарии, которые, в принципе, здесь и не нужны, оставив лишь пару пустых строк для лучшей читабельности то получится нечто наподобие такого:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
if(isset($_POST['кнопка_формы']))
{
    if( isset($_POST['login'], $_POST['password']) )
    {
        $login = mysql_real_escape_string(stripslashes(trim($_POST['login'])));
        $password = mysql_real_escape_string(stripslashes(trim($_POST['password'])));
 
        if(empty($login) || empty($password))
            echo 'Вы заполнили не все поля!';
        else
        {
            if( ($result = mysql_query('SELECT COUNT(1) FROM `users` WHERE `login`="'.$login.'"')) )
                $data = mysql_fetch_array($result,MYSQL_NUM);
 
            if(!empty($data[0]))
                echo 'Пользователь с таким логином уже существует!';
            else
            {
                mysql_query ('INSERT INTO `users` (`login`,`password`) VALUES("'.$login.'","'.$password.'")');
                echo -1 !== mysql_affected_rows()
                    ? 'Вы успешно зарегистрированы! Теперь вы можете зайти на сайт.<br />
                        <a href="./">Главная страница</a>'
                    : 'Произошла ошибка при регистрации. Пожалуйста, попробуйте позднее.';
            }
        }
    }
    else 
       echo 'Вы заполнили не все данные';
}
ну и можно избавиться от первого if-a, он, в принципе, не так уж и важен.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
if( isset($_POST['login'], $_POST['password']) )
{
    $login = mysql_real_escape_string(stripslashes(trim($_POST['login'])));
    $password = mysql_real_escape_string(stripslashes(trim($_POST['password'])));
 
    if(empty($login) || empty($password))
        echo 'Вы заполнили не все поля!';
    else
    {
        if( ($result = mysql_query('SELECT COUNT(1) FROM `users` WHERE `login`="'.$login.'"')) )
            $data = mysql_fetch_array($result,MYSQL_NUM);
 
        if(!empty($data[0]))
            echo 'Пользователь с таким логином уже существует!';
        else
        {
            mysql_query ('INSERT INTO `users` (`login`,`password`) VALUES("'.$login.'","'.$password.'")');
            echo -1 !== mysql_affected_rows()
                ? 'Вы успешно зарегистрированы! Теперь вы можете зайти на сайт.<br />
                    <a href="./">Главная страница</a>'
                : 'Произошла ошибка при регистрации. Пожалуйста, попробуйте позднее.';
        }
    }
}
else 
    echo 'Вы заполнили не все данные';
22
DrobyshevAlex
1170 / 1120 / 16
Регистрация: 31.05.2012
Сообщений: 3,059
19.09.2012, 13:27 #5
Хотелось бы рассказать о некоторых ошибках в php с использованием условий и логический операций.

Приходилось мне видеть что то типа вот такого:
PHP
1
$username = $user->getUserName() || 'Гость';
А ещё вот такого:
PHP
1
$user->hasGift(CONST_GIFT_1 || CONST_GIFT_2); // CONST_GIFT_1 и CONST_GIFT_2 - какие то числа, id подарков
Первый код в некоторых языках, например JS или Ruby будет прекрасно работать, а в php он будет работать скорей всего не так как ожидал тот, кто его написал.
||, &&, or, and, <, >, ==, ... - применяются для логических операций, и результатом выполнения будет всегда логическое значение.
не важно какие были переменные.
PHP
1
2
3
4
$a = 1;
$b = 'abc';
$c = $a && $b;
var_dump($c); // $c будет true
Отсюда следует что $user->getUserName() || 'Гость' - вернёт логическое значение, то есть $username будет иметь тип boolean.
Можно с увереностью сказать, что $username будет равно true, так как даже если $user->getUserName() вернёт false то (bool)'Гость' всегда вернёт true.

То же самое и во втором пример, с вызовом функции hasGift().
Если хотя бы одно число не равно 0 то там будет передано в функцию true, а функция ожидает тип int, по этому в функции будет проверка (int)true = 1, то есть будет проверено, есть ли у юзера подарок с ID = 1.
В результате функция выполнится, и проверка пройдёт, но не того чего нужно, и такую ошибку можно будет не сразу отловить и заметить что она есть.

Теперь рассмотрим оператор switch.
Пусть у нас будет код:
PHP
1
2
3
4
5
6
switch ($a)
{
    case ($a > 0 and $a <= 10): echo 'Условие 1'; break;
    case ($a > 10 and $a <= 20): echo 'Условие 2'; break;
    default: echo 'default';
}
При $a от 1 до 10
PHP
1
($a > 0 and $a <= 10) = true
Так как switch сравнивает == (не строгим сравнением), то будет приведение типов.
PHP
1
($bool)$a = true
Выпонится условие 1.

При $a от 11 до 20
PHP
1
2
3
($a > 0 and $a <= 10) = false
($bool)$a = true
($a > 10 and $a <= 20) = true
Выполнится условие 2

При $a > 20
PHP
1
2
3
($a > 0 and $a <= 10) = false
($bool)$a = true
($a > 10 and $a <= 20) = false
Выполнится дейтсвие default

Вроде бы всё верно, но если взять $a = 0
PHP
1
2
($a > 0 and $a <= 10) = false
($bool)$a = false
Выполнится условие 1! Вот такие ошибки трудно отловить в процессе работы сайта. У вас будут возникать ошибки, но трудно будет найти почему.

А если добавить в начало вот такую строку
PHP
1
case true:  echo 'Условие 0'; break;
То при $a = 0 будет условие 1 выполняться, а при любых других числах - условие 0, других вариантов не будет.

Ну и последнее о чём хотелось бы напомнить, это о третьем параметре функции in_array, там тоже бывает беда из за приведения типов.
Напрмиер:
PHP
1
2
3
$a = array(0, 'Вася');
$s = 'Петя';
var_dump(in_array($s, $a)); // результат true!
Так как при сравнении 0 с переменной $s - тип переменной $s будет приведён к int, (int)'Петя' = 0, а 0 в массиве есть.
Или
PHP
1
2
3
$a = array(true, 'Вася');
$s = 'Петя';
var_dump(in_array($s, $a)); // результат true!
true - boolean
(bool)'Петя' = true

true в массиве есть.

Что бы не было такого, есть у функции in_array третий параметр, который заставляет сравнивать с учётом типа переменных.

PHP
1
2
3
$a = array(true, 'Вася');
$s = 'Петя';
var_dump(in_array($s, $a, true)); // результат false
19
mifirakus
0 / 0 / 0
Регистрация: 12.06.2013
Сообщений: 11
12.06.2013, 16:08 #6
спасибо вам огромное.благодаря вам у меня меньше головной боли стало.
0
Forastero
538 / 320 / 35
Регистрация: 15.05.2013
Сообщений: 774
Записей в блоге: 1
22.06.2013, 07:39 #7
Замечательный топик.
Огромное спасибо каждому за проделанную работу.
Поверьте, она выполнена не даром.
0
SanchO-SEK
61 / 23 / 3
Регистрация: 22.05.2012
Сообщений: 87
22.12.2014, 04:44 #8
Хотелось бы добавить несколько слов насчет сравнения с учетом типа. Однажды писал авторизацию/регистрацию и в части авторизации отчасти было следующее: если пользователь подтвердил E-mail перейдя по ссылке из отправленного письма - он может авторизоваться, иначе после ввода логина и пароля пользователю показывалась ошибка о том, что учетная запись еще не активирована. Проверка проверялась примерно так (дословно уже не припомню, но суть передам и таким примером):
...
PHP
1
2
3
4
5
// после получения данных от БД:
$data = mysqli_fetch_assoc($result);
// В ячейке isActivated должно быть 1/0 - активировано/не активировано соответственно
if(1 !== $data['isActivated'])
   exit('E-mail еще не подтвержден. Учетная запись не активирована!');
...
В тот момент будучи учеником в С++ у меня выработалась некоторая "паранойя" по поводу типов данных, поэтому в PHP я сравнивал данные с учетом типа. В коде выше у меня была семантическая ошибка в том, что данные из БД приходили в типе STRING (а я ведь почему то был уверен, что это был INT) и затем сравнивались с INT - естественно, возвращалось FALSE и код работал неправильно. Около половины дня потратил на поиск этой ошибки :-(
Мораль данной ситуации в том, что сравнивать данные с учетом типа тоже нужно с некоторой аккуратностью
0
KOPOJI
Эксперт HTML/CSSЭксперт PHP
16702 / 6624 / 433
Регистрация: 12.06.2012
Сообщений: 19,879
Завершенные тесты: 1
22.12.2014, 07:57  [ТС] #9
Цитата Сообщение от SanchO-SEK Посмотреть сообщение
Мораль данной ситуации в том, что сравнивать данные с учетом типа тоже нужно с некоторой аккуратностью
Мораль, скорее, в том, что сравнение с учетом типа надо использовать тогда, когда ты точно знаешь, какой тип ожидается в ответ.
А вообще, особенно после статически типизированных языков, нужно с еще большей внимательностью относиться к типам данных (вопреки некоторым мнениям, что динамическая типизация в разы лучше), т.к. компилятор языка PHP не предупредит о сравнении данных с разными типами, как при использовании статической типизации.
Хотя, признаться, в некоторых языках с динамической типизацией, все же, есть некая проверка типов. Например, в лиспе подобный код выдаст ошибку, что foo не является числом
Lisp
1
2
3
(setq f 'foo)
(setq b 10)
(print (= f b))
https://ideone.com/yI4imG
0
22.12.2014, 07:57
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.12.2014, 07:57
Привет! Вот еще темы с ответами:

С++11 и С++14 FAQ - C++
На сайте http://isocpp.org/ был опубликован анонс нового C++ FAQ. Материал довольно объемный и содержит разделы для начинающих, вопросы...

FAQ по С++ - C++
У кого есть FAQ по библиотекам и входящим в них функциям(что они делают). Дайте ссылку плиз.

=FAQ= - Электроника
Частые вопросы на Изеэлектрониксе, и ответы к ним. В: Что почитать начинающему нелёгкое дело пайки и программирования, с чего начать?...

FAQ по Qt - C++ Qt
В данной теме приведены самые часто задаваемые вопросы по Qt и Qt Creator. Где скачать Qt/Qt Creator. Как обновить Qt. ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.