Форум программистов, компьютерный форум, киберфорум
Наши страницы
PHP для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 232, средняя оценка - 4.94
KOPOJI
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16744 / 6635 / 860
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 1
#1

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

07.09.2012, 16:05. Просмотров 36007. Ответов 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 по распространенным ошибкам"
Вопрос по теме...

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

FAQ
Не могу скачать документацию...

Preg_replace() FAQ?
хз, какая то хрень и не пойму в чем дело. Может кто подскажет, как так то ))...

Гоняет по 2 ошибкам
1) Первая ошибка &quot; Unit1.cpp(24): E2316 '_fastcall TForm1::FormCreate(TObject...

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

8
crautcher
2018 / 1990 / 463
Регистрация: 27.05.2011
Сообщений: 6,835
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
2018 / 1990 / 463
Регистрация: 27.05.2011
Сообщений: 6,835
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
16744 / 6635 / 860
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 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
1171 / 1121 / 94
Регистрация: 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
541 / 323 / 81
Регистрация: 15.05.2013
Сообщений: 781
Записей в блоге: 1
22.06.2013, 07:39 #7
Замечательный топик.
Огромное спасибо каждому за проделанную работу.
Поверьте, она выполнена не даром.
0
SanchO-SEK
61 / 23 / 7
Регистрация: 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
16744 / 6635 / 860
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 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
Привет! Вот еще темы с решениями:

Справочник по ошибкам Post платы
Здравствуйте необходимо создать справочник по ошибкам Post платы ,нашел только...

Сма Bauknecht WA 7540, Поделитесь информацией по ошибкам
Должен буду идти на вызов. Клиент говорит, что сма выдаёт ошибку. Но дисплея на...

Сма Blomberg WNF 8447 нужна инфа по ошибкам
Сма Blomberg WNF 8447 нужна инфа по ошибкам ,заранее спасибо. ...

сма Whirlpool AWE 6514 859365110040, нужны данные по ошибкам
Приветствую всех! Машинка не переходит на полоскание. Нужна расшифровка по...


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

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

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