Безобразный user info php. Недомыслие. Что он делает

$HTTP_SERVER_VARS [удалено]

(PHP 4 >= 4.1.0, PHP 5, PHP 7)

$_SERVER -- $HTTP_SERVER_VARS [удалено] Информация о сервере и среде исполнения

Описание

Переменная $_SERVER - это массив, содержащий информацию, такую как заголовки, пути и местоположения скриптов. Записи в этом массиве создаются веб-сервером. Нет гарантии, что каждый веб-сервер предоставит любую из них; сервер может опустить некоторые из них или предоставить другие, не указанные здесь. Тем не менее, многие эти переменные присутствуют в » спецификации CGI/1.1 , так что вы можете их ожидать их реализации и в конкретном веб-сервере.

Переменная $HTTP_SERVER_VARS содержит ту же начальную информацию, но она не суперглобальная . (Заметьте, что $HTTP_SERVER_VARS и $_SERVER являются разными переменными, так что PHP обрабатывает их соответственно). Также учтите, что "длинные массивы" были удалены в версии PHP 5.4.0, поэтому $HTTP_SERVER_VARS больше не существует.

Индексы

Вы можете найти (а можете и не найти) любой из следующих элементов в массиве $_SERVER . Заметьте, что немногие элементы, если вообще такие найдутся, будут доступны (или действительно будут иметь значение), если PHP запущен в командной строке .

" PHP_SELF " Имя файла скрипта, который сейчас выполняется, относительно корня документов. Например, $_SERVER["PHP_SELF"] в скрипте по адресу http://example.com/foo/bar.php будет /foo/bar.php . Константа __FILE__ содержит полный путь и имя файла текущего (то есть подключенного) файла. Если PHP запущен в командной строке, эта переменная содержит имя скрипта, начиная с PHP 4.3.0. Раньше она была недоступна. "argv " Массив аргументов, переданных скрипту. Когда скрипт запущен в командой строке, это дает C-подобный доступ к параметрам командной строки. Когда вызывается через метод GET, этот массив будет содержать строку запроса. "argc " Содержит количество параметров, переданных скрипту (если запуск произведен в командной строке). " GATEWAY_INTERFACE " Содержит используемую сервером версию спецификации CGI; к примеру"CGI/1.1 ". " SERVER_ADDR " IP адрес сервера, на котором выполняется текущий скрипт. " SERVER_NAME " Имя хоста, на котором выполняется текущий скрипт. Если скрипт выполняется на виртуальном хосте, здесь будет содержатся имя, определенное для этого виртуального хоста. " SERVER_SOFTWARE " Строка идентификации сервера, указанная в заголовках, когда происходит ответ на запрос. " SERVER_PROTOCOL " Имя и версия информационного протокола, через который была запрошена страница; к примеру "HTTP/1.0 "; " REQUEST_METHOD " Какой метод был использован для запроса страницы; к примеру "GET ", "HEAD ", "POST ", "PUT ".

Замечание :

PHP скрипт завершается после посылки заголовков (то есть после того, как осуществляет любой вывод без буферизации вывода), если запрос был осуществлен методом HEAD .

" REQUEST_TIME " Временная метка начала запроса. Доступна, начиная с PHP 5.1.0. " REQUEST_TIME_FLOAT " Временная метка начала запроса с точностью до микросекунд. Доступна, начиная с PHP 5.4.0. " QUERY_STRING " Строка запросов, если есть, с помощью которой была получена страница. " DOCUMENT_ROOT " Директория корня документов, в которой выполняется текущий скрипт, в точности та, которая указана в конфигурационном файле сервера. " HTTP_ACCEPT " Содержимое заголовка Accept: из текущего запроса, если он есть. " HTTP_ACCEPT_CHARSET " Содержимое заголовка Accept-Charset: из текущего запроса, если он есть. Например: "iso-8859-1,*,utf-8 ". " HTTP_ACCEPT_ENCODING " Содержимое заголовка Accept-Encoding: gzip ". " HTTP_ACCEPT_LANGUAGE " Содержимое заголовка Accept-Language: из текущего запроса, если он есть. Например: "en ". " HTTP_CONNECTION " Содержимое заголовка Connection: из текущего запроса, если он есть. Например: "Keep-Alive ". " HTTP_HOST " Содержимое заголовка Host: из текущего запроса, если он есть. " HTTP_REFERER " Адрес страницы (если есть), которая привела браузер пользователя на эту страницу. Этот заголовок устанавливается веб-браузером пользователя. Не все браузеры устанавливают его и некоторые в качестве дополнительной возможности позволяют изменять содержимое заголовка HTTP_REFERER . Одним словом, в самом деле ему нельзя доверять. " HTTP_USER_AGENT " Содержимое заголовка User-Agent: из текущего запроса, если он есть. Эта строка содержит обозначение браузера, которым пользователь запросил данную страницу. Типичным примером является строка: Mozilla/4.5 (X11; U; Linux 2.2.9 i586) . Среди прочего, вы можете использовать это значение с функцией get_browser() чтобы адаптировать вывод вашей страницы к возможностям браузера пользователя " HTTPS " Принимает непустое значение, если запрос был произведен через протокол HTTPS.

Замечание : Обратите внимание, что при использовании ISAPI с IIS значение будет off , если запрос не был произведен через протокол HTTPS.

" REMOTE_ADDR " IP-адрес, с которого пользователь просматривает текущую страницу. " REMOTE_HOST " Удаленный хост, с которого пользователь просматривает текущую страницу. Обратный просмотр DNS базируется на значении переменной REMOTE_ADDR .

Замечание : Ваш веб-сервер должен быть настроен, чтобы создавать эту переменную. Для примера, в Apache вам необходимо присутствие директивы HostnameLookups On в файле httpd.conf , чтобы эта переменная создавалась. См. также gethostbyaddr() .

" REMOTE_PORT " Порт на удаленной машине, который используется для связи с веб-сервером. " REMOTE_USER " Аутентифицированный пользователь. " REDIRECT_REMOTE_USER " Аутентифицированный пользователь, если запрос был перенаправлен изнутри. " SCRIPT_FILENAME "

Абсолютный путь к скрипту, который в данный момент исполняется.

Замечание :

Если скрипт запускается в командной строке (CLI), используя относительный путь, такой как file.php или../file.php , переменная $_SERVER["SCRIPT_FILENAME"] будет содержать относительный путь, указанный пользователем.

" SERVER_ADMIN " Эта переменная получает свое значение (для Apache) из директивы конфигурационного файла сервера. Если скрипт запущен на виртуальном хосте, это будет значение, определенное для данного виртуального хоста. " SERVER_PORT " Порт на компьютере сервера, используемый веб-сервером для соединения. Для установок по умолчанию, значение будет "80 "; используя SLL, например, это значение будет таким, какое сконфигурировано для соединений безопасного HTTP.

Замечание : Чтобы получить физический (реальный) порт в Apache 2, необходимо установить UseCanonicalName = On и UseCanonicalPhysicalPort = On , иначе это значение может быть подменено и не вернуть реальной значение физического порта. Полагаться на это значение небезопасно в контексте приложений, требующих усиленной безопасности.

" SERVER_SIGNATURE " Строка, содержащая версию сервера и имя виртуального хоста, которые добавляются к генерируемым сервером страницам, если включено. " PATH_TRANSLATED " Filesystem- (not document root-) based path to the current script, after the server has done any virtual-to-real mapping.

Замечание : Начиная с PHP 4.3.2, переменная PATH_TRANSLATED больше не устанавливается неявно в Apache 2 SAPI , по сравнению с Apache версии 1, где она устанавливается в то же самое значение, что и переменная SCRIPT_FILENAME , когда она не используется Apache. Это изменение было сделано для соответствия спецификации CGI , где переменная PATH_TRANSLATED должна существовать только тогда, когда PATH_INFO определена. Пользователи Apache 2 могут использовать директиву AcceptPathInfo = On в конфигурационном файле httpd.conf для задания переменной PATH_INFO .

" SCRIPT_NAME " Содержит путь, к текущему исполняемому скрипту. Это полезно для страниц, которые должны указывать на самих себя. Константа __FILE__ содержит полный путь и имя текущего (т.е. включаемого) файла. " REQUEST_URI " URI, который был передан для того, чтобы получить доступ к этой странице. Например, "/index.html ". " PHP_AUTH_DIGEST " При выполнении HTTP Digest аутентификации, этой переменной присваивается заголовок "Authorization", который присылается клиентом (его необходимо потом использовать для соответствующей валидации). " PHP_AUTH_USER " Когда выполняется HTTP-аутентификация, этой переменной присваивается имя пользователя, предоставленное пользователем. " PHP_AUTH_PW " Когда выполняется HTTP-аутентификация, этой переменной присваивается пароль, предоставленный пользователем. " AUTH_TYPE " Когда выполняется HTTP-аутентификация, этой переменной присваивается тип аутентификации, который используется. " PATH_INFO " Содержит любой предоставленный пользователем путь, содержащийся после имени скрипта, но до строки запроса, если доступно. Например, если текущий скрипт запрошен по URL http://www.example.com/php/path_info.php/some/stuff?foo=bar , то переменная $_SERVER["PATH_INFO"] будет содержать /some/stuff ?>

Результатом выполнения данного примера будет что-то подобное.

Для начала мы усовершенствуем страничку регистрации, добавив возможность загружать аватар. Исходное изображение должно быть формата jpg, gif или png. Так же оно должно быть не более 2 Мб. Не беспокойтесь, после его сжатия скриптом, размер аватара будет около 3 кб и формат jpg. Откройте страницу reg. php и допишите в теге < form > строчку enctype="multipart/form-data" ,как в примере:


Регистрация










Теперь сохраняем reg.php

2.Затем необходимо создать еще одно поле в таблице users . Заходим в phpmyadmin , выбираем нужную базу и таблицу.


Выставляем все значения, как на рисунке:

В это поле будет записываться путь до аватара, а сам он сохраняется в отдельную папку, назовем ее «avatars». Папка будет расположена в том же каталоге, что и остальные файлы скрипта.

3.Переходим к файлу save _ user . php и дописываем следующий код после удаления пробелов у логина и пароля:

//удаляем лишние пробелы
$login = trim($login);

// дописываем новое********************************************

//добавляем проверку на длину логина и пароля
if (strlen($login) < 3 or strlen($login) > 15) {
exit ("Логин должен состоять не менее чем из 3 символов и не более чем из 15.");
}
if (strlen($password) < 3 or strlen($password) > 15) {
exit ("Пароль должен состоять не менее чем из 3 символов и не более чем из 15.");
}

if (!empty($_POST["fupload"])) //проверяем, отправил ли пользователь изображение
{
$fupload=$_POST["fupload"]; $fupload = trim($fupload);
if ($fupload =="" or empty($fupload)) {
unset($fupload);// если переменная $fupload пуста, то удаляем ее
}
}
if (!isset($fupload) or empty($fupload) or $fupload =="")
{
//если переменной не существует (пользователь не отправил изображение),то присваиваем ему заранее приготовленную картинку с надписью "нет аватара"
$avatar = "avatars/net-avatara.jpg"; //можете нарисовать net-avatara.jpg или взять в исходниках
}
else
{
//иначе - загружаем изображение пользователя
$path_to_90_directory = "avatars/";//папка, куда будет загружаться начальная картинка и ее сжатая копия

If(preg_match("/[.](JPG)|(jpg)|(gif)|(GIF)|(png)|(PNG)$/",$_FILES["fupload"]["name"]))//проверка формата исходного изображения
{
$filename = $_FILES["fupload"]["name"];
$source = $_FILES["fupload"]["tmp_name"];
$target = $path_to_90_directory . $filename;
move_uploaded_file($source, $target);//загрузка оригинала в папку $path_to_90_directory
if(preg_match("/[.](GIF)|(gif)$/", $filename)) {
$im = imagecreatefromgif($path_to_90_directory.$filename) ; //если оригинал был в формате gif, то создаем изображение в этом же формате. Необходимо для последующего сжатия
}
if(preg_match("/[.](PNG)|(png)$/", $filename)) {
$im = imagecreatefrompng($path_to_90_directory.$filename) ;//если оригинал был в формате png, то создаем изображение в этом же формате. Необходимо для последующего сжатия
}

If(preg_match("/[.](JPG)|(jpg)|(jpeg)|(JPEG)$/", $filename)) {
$im = imagecreatefromjpeg($path_to_90_directory.$filename); //если оригинал был в формате jpg, то создаем изображение в этом же формате. Необходимо для последующего сжатия
}
//СОЗДАНИЕ КВАДРАТНОГО ИЗОБРАЖЕНИЯ И ЕГО ПОСЛЕДУЮЩЕЕ СЖАТИЕ ВЗЯТО С САЙТА www.codenet.ru
// Создание квадрата 90x90
// dest - результирующее изображение
// w - ширина изображения
// ratio - коэффициент пропорциональности
$w = 90; // квадратная 90x90. Можно поставить и другой размер.
// создаём исходное изображение на основе
// исходного файла и определяем его размеры
$w_src = imagesx($im); //вычисляем ширину
$h_src = imagesy($im); //вычисляем высоту изображения
// создаём пустую квадратную картинку
// важно именно truecolor!, иначе будем иметь 8-битный результат
$dest = imagecreatetruecolor($w,$w);
// вырезаем квадратную серединку по x, если фото горизонтальное
if ($w_src>$h_src)
imagecopyresampled($dest, $im, 0, 0,
round((max($w_src,$h_src)-min($w_src,$h_src))/2),
0, $w, $w, min($w_src,$h_src), min($w_src,$h_src));
// вырезаем квадратную верхушку по y,
// если фото вертикальное (хотя можно тоже серединку)
if ($w_src<$h_src)
imagecopyresampled($dest, $im, 0, 0, 0, 0, $w, $w,
min($w_src,$h_src), min($w_src,$h_src));
// квадратная картинка масштабируется без вырезок
if ($w_src==$h_src)
imagecopyresampled($dest, $im, 0, 0, 0, 0, $w, $w, $w_src, $w_src);
$date=time(); //вычисляем время в настоящий момент.
imagejpeg($dest, $path_to_90_directory.$date.".jpg");//сохраняем изображение формата jpg в нужную папку, именем будет текущее время. Сделано, чтобы у аватаров не было одинаковых имен.
//почему именно jpg? Он занимает очень мало места + уничтожается анимирование gif изображения, которое отвлекает пользователя. Не очень приятно читать его комментарий, когда краем глаза замечаешь какое-то движение.
$avatar = $path_to_90_directory.$date.".jpg";//заносим в переменную путь до аватара.
$delfull = $path_to_90_directory.$filename;
unlink ($delfull);//удаляем оригинал загруженного изображения, он нам больше не нужен. Задачей было - получить миниатюру.
}
else
{
//в случае несоответствия формата, выдаем соответствующее сообщение
exit ("Аватар должен быть в формате JPG,GIF или PNG");
}
//конец процесса загрузки и присвоения переменной $avatar адреса загруженной авы
}



// дописали новое********************************************
// Далее идет все из первой части статьи,но необходимо дописать изменение в запрос к базе.
//подключаемся к базе
// проверка на существование пользователя с таким же логином
$result = mysql_query("SELECT id FROM users WHERE login="$login"",$db);
if (!empty($myrow["id"])) {
exit ("Извините, введённый вами логин уже зарегистрирован. Введите другой логин.");
}
// если такого нет, то сохраняем данные
$result2 = mysql_query ("INSERT INTO users (login,password,avatar) VALUES("$login","$password","$avatar")");
// Проверяем, есть ли ошибки
if ($result2=="TRUE")
{
echo "Вы успешно зарегистрированы! Теперь вы можете зайти на сайт. Главная страница";
}
else {
echo "Ошибка! Вы не зарегистрированы.";
}
?>

4. Необходимо добавить одну таблицу в ту же базу. В ней будут хранится ip-адреса, которые допустили ошибки при входе. Таким образом мы сможем ограничить доступ тем, кто ошибся больше трёх раз подряд на минут 15. Думаю программам, подбирающим пароли, долго придется возиться.
Зайдем в phpmyadmin и создадим новую таблицу с 3-мя полями:


ip - ip-адрес.
date - дата неудачного входа за последние 15 минут у пользователя с данным ip. col - количество ошибок за последние 15 минут у пользователя с данным ip.
Отлично! Готово, теперь изменим файл проверки логина и пароля, ведь теперь у нас пароль зашифрован. Открываем testreg.php и удаляем все, что дальше удаления пробелов с логина и пароля. Далее добавляем следующий код:

//удаляем лишние пробелы
$login = trim($login);
$password = trim($password);

// заменяем новым********************************************
// подключаемся к базе
include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь
// минипроверка на подбор паролей
$ip=getenv("HTTP_X_FORWARDED_FOR");
if (empty($ip) || $ip=="unknown") { $ip=getenv("REMOTE_ADDR"); }//извлекаем ip
mysql_query ("DELETE FROM oshibka WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date) > 900");//удаляем ip-адреса ошибавшихся при входе пользователей через 15 минут.
$result = mysql_query("SELECT col FROM oshibka WHERE ip="$ip"",$db);// извлекаем из базы количество неудачных попыток входа за последние 15 у пользователя с данным ip
$myrow = mysql_fetch_array($result);
if ($myrow["col"] > 2) {
//если ошибок больше двух, т.е три, то выдаем сообщение.
exit("Вы набрали логин или пароль неверно 3 раз. Подождите 15 минут до следующей попытки.");
}
$password = md5($password);//шифруем пароль
$password = strrev($password);// для надежности добавим реверс
$password = $password."b3p6f";
//можно добавить несколько своих символов по вкусу, например, вписав "b3p6f". Если этот пароль будут взламывать методом подбора у себя на сервере этой же md5,то явно ничего хорошего не выйдет. Но советую ставить другие символы, можно в начале строки или в середине.
//При этом необходимо увеличить длину поля password в базе. Зашифрованный пароль может получится гораздо большего размера.

$result = mysql_query("SELECT * FROM users WHERE login="$login" AND password="$password"",$db); //извлекаем из базы все данные о пользователе с введенным логином и паролем
$myrow = mysql_fetch_array($result);
if (empty($myrow["id"]))
{
//если пользователя с введенным логином и паролем не существует
//Делаем запись о том, что данный ip не смог войти.
$select = mysql_query ("SELECT ip FROM oshibka WHERE ip="$ip"");
$tmp = mysql_fetch_row ($select);
if ($ip == $tmp) {//проверяем, есть ли пользователь в таблице "oshibka"
$result52 = mysql_query("SELECT col FROM oshibka WHERE ip="$ip"",$db);
$myrow52 = mysql_fetch_array($result52);
$col = $myrow52 + 1;//прибавляем еще одну попытку неудачного входа
mysql_query ("UPDATE oshibka SET col=$col,date=NOW() WHERE ip="$ip"");
}
else {
mysql_query ("INSERT INTO oshibka (ip,date,col) VALUES ("$ip",NOW(),"1")");
//если за последние 15 минут ошибок не было, то вставляем новую запись в таблицу "oshibka"
}

exit ("Извините, введённый вами логин или пароль неверный.");
}
else {
nbsp; //если пароли совпадают, то запускаем пользователю сессию! Можете его поздравить, он вошел!
$_SESSION["password"]=$myrow["password"];
$_SESSION["login"]=$myrow["login"];
$_SESSION["id"]=$myrow["id"];//эти данные очень часто используются, вот их и будет "носить с собой" вошедший пользователь

//Далее мы запоминаем данные в куки, для последующего входа.
//ВНИМАНИЕ!!! ДЕЛАЙТЕ ЭТО НА ВАШЕ УСМОТРЕНИЕ, ТАК КАК ДАННЫЕ ХРАНЯТСЯ В КУКАХ БЕЗ ШИФРОВКИ
if ($_POST["save"] == 1) {
//Если пользователь хочет, чтобы его данные сохранились для последующего входа, то сохраняем в куках его браузера
setcookie("login", $_POST["login"], time()+9999999);
setcookie("password", $_POST["password"], time()+9999999);
}}
echo "";//перенаправляем пользователя на главную страничку, там ему и сообщим об удачном входе
?>

5. Полностью изменим главную страничку. Необходимо на ней вывести аватар пользователя, вывести ссылку на выход из аккаунта и добавить чекбокс для запоминания пароля при входе.
Index.php

// вся процедура работает на сессиях. Именно в ней хранятся данные пользователя, пока он находится на сайте. Очень важно запустить их в самом начале странички!!!
session_start();
include ("bd.php");// файл bd.php должен быть в той же папке, что и все остальные, если это не так, то просто измените путь
if (!empty($_SESSION["login"]) and !empty($_SESSION["password"]))
{
//если существует логин и пароль в сессиях, то проверяем их и извлекаем аватар
$login = $_SESSION["login"];
$password = $_SESSION["password"];
$result = mysql_query("SELECT id,avatar FROM users WHERE login="$login" AND password="$password"",$db);
$myrow = mysql_fetch_array($result);
//извлекаем нужные данные о пользователе
}
?>


Главная страница


Главная страница

if (!isset($myrow["avatar"]) or $myrow["avatar"]=="") {
//проверяем, не извлечены ли данные пользователя из базы. Если нет, то он не вошел, либо пароль в сессии неверный. Выводим окно для входа. Но мы не будем его выводить для вошедших, им оно уже не нужно.
print <<


HERE;

If (isset($_COOKIE["login"])) //есть ли переменная с логином в COOKIE. Должна быть, если пользователь при предыдущем входе нажал на чекбокс "Запомнить меня"
{
//если да, то вставляем в форму ее значение. При этом пользователю отображается, что его логин уже вписан в нужную графу
echo " value="".$_COOKIE["login"]."">";
}

print <<




HERE;

If (isset($_COOKIE["password"]))//есть ли переменная с паролем в COOKIE. Должна быть, если пользователь при предыдущем входе нажал на чекбокс "Запомнить меня"
{
//если да, то вставляем в форму ее значение. При этом пользователю отображается, что его пароль уже вписан в нужную графу
echo " value="".$_COOKIE["password"]."">";
}

Print <<



Запомнить меня.






Зарегистрироваться



Вы вошли на сайт, как гость

HERE;
}
else
{
//при удачном входе пользователю выдается все, что расположено ниже между звездочками.

print <<
Вы вошли на сайт, как $_SESSION (выход)


Эта ссылка доступна только зарегистрированным пользователям

Ваш аватар:




HERE;

//************************************************************************************
//при удачном входе пользователю выдается все, что расположено ВЫШЕ между звездочками.
}
?>

6. Необходимо сделать возможность выйти из аккаунта пользователям, которые вошли. На главной странице уже была ссылка на выход. Но этого файла пока не существует. Так создадим новый файл exit.php с кодом:

session_start();
if (empty($_SESSION["login"]) or empty($_SESSION["password"]))
{
//если не существует сессии с логином и паролем, значит на этот файл попал невошедший пользователь. Ему тут не место. Выдаем сообщение об ошибке, останавливаем скрипт
exit ("Доступ на эту страницу разрешен только зарегистрированным пользователям. Если вы зарегистрированы, то войдите на сайт под своим логином и паролем
Главная страница");
}

unset($_SESSION["password"]);
unset($_SESSION["login"]);
unset($_SESSION["id"]);// уничтожаем переменные в сессиях
exit("");
// отправляем пользователя на главную страницу.
?>

Ну вот и все! Пользуйтесь на здоровье! Удачи!

Во втором уроке мы напишем еще два класса и полностью закончим внутреннюю часть скрипта.

План

Цель серии уроков создать простое приложение, которое позволяет пользователям регистрироваться, входить, выходить и менять настройки. Класс, который будет содержать всю информации о пользователе будет называться User и он будет определен в файле User.class.php. Класс, который будет отвечать за вход\выход будет называться UserTools (UserTools.class.php).

Немного про именование классов

Правильным тоном является называть файлы с описанием класса таким же именем как и сам класс. Таким образом легко определить цель каждого файла в папке с классами.

Также обычно в конце названия файла класса добавляют.class или.inc. Таким образом мы четко определяем предназначение файла и можем с помощью.htaccess ограничить доступ к этим файлам.

Класс Пользователей (User.class.php)

Этот класс будет определять каждого пользователя. С ростом данного приложения определение "Пользователь" может существенно измениться. К счастью, ООП программирование позволяет легко добавлять дополнительные атрибуты пользователей.

Конструктор

В этом классе мы будем использовать конструктор - это функция, которая автоматически вызывается при создании очередной копии класса. Это позволяет нам автоматически публиковать некоторые атрибуты после создания проекта. В этом классе конструктор будет брать единственный аргумент: ассоциативный массив, который содержит один ряд из таблицы users нашей БД.

require_once "DB.class.php"; class User { public $id; public $username; public $hashedPassword; public $email;
public $joinDate;
//Конструктор вызывается при создании нового объекта //Takes an associative array with the DB row as an argument. function __construct($data) { $this->id = (isset($data["id"])) ? $data["id"] : ""; $this->username = (isset($data["username"])) ? $data["username"] : ""; $this->hashedPassword = (isset($data["password"])) ? $data["password"] : ""; $this->email = (isset($data["email"])) ? $data["email"] : ""; $this->joinDate = (isset($data["join_date"])) ? $data["join_date"] : ""; }
public function save($isNewUser = false) { //create a new database object. $db = new DB(); //if the user is already registered and we"re //just updating their info. if(!$isNewUser) { //set the data array $data = array("username" => ""$this->username"", "password" => ""$this->hashedPassword"",
"email" => ""$this->email"");
//update the row in the database $db->update($data, "users", "id = ".$this->id); }else { //if the user is being registered for the first time. $data = array("username" => ""$this->username"", "password" => ""$this->hashedPassword"", "email" => ""$this->email"", "join_date" => """.date("Y-m-d H:i:s",time())."""); $this->id = $db->insert($data, "users"); $this->joinDate = time(); } return true; } } ?>

Объяснение

Первая часть кода, вне зоны класса, обеспечивает подключение класса в БД (поскольку в классе User есть функция, которая требует этот класс).

Вместо переменных класса “protected” (использовались в 1-м уроке) мы определяем их как “public”. Это означает, что любой код вне класса имеет доступ к этим переменным при работе с объектом User.

Конструктор берет массив, в котором колонки в таблице являются ключами. Мы задаем переменную класса используя $this->variablename. В примере данного класса, мы прежде всего проверяем существует ли значение определенного ключа. Если да, тогда мы приравниваем переменную класса к этому значению. В противном случае - пустая строка. Код использует краткую форму записи оборота if:

$value = (3 == 4) ? "A" : "B";

В данном примере мы проверяем равняется ли 3 четырем! Если да - тогда $value = “A”, нет - $value = “B”. В нашем примере результат $value = “B”.

Сохраняем Информацию о Пользователях в БД

Функция сохранения используется для внесения изменений в таблицу БД с текущими значениями в объекте User. Эта функция использует класс БД, который мы создали в первом уроке. Используя переменные класса, устанавливается массив $data. Если данные о пользователе сохраняются впервые, тогда $isNewUser передается как $true (по умолчанию false). Если $isNewUser = $true, тогда вызывается функция insert() класса DB. В противном случае вызывается функция update(). В обоих случаях информация от объекта user будет сохранена в БД.

Класс UserTools.class.php

Этот класс будет содержать функции, которые имеют отношение к пользователям: login(), logout(), checkUsernameExists() и get(). Но с расширением данного приложения, Вы можете добавить еще множество других.

//UserTools.class.php require_once "User.class.php"; require_once "DB.class.php";
class UserTools {
//Log the user in. First checks to see if the //username and password match a row in the database. //If it is successful, set the session variables //and store the user object within.
public function login($username, $password)
{
$hashedPassword = md5($password); $result = mysql_query("SELECT * FROM users WHERE username = "$username" AND password = "$hashedPassword""); if(mysql_num_rows($result) == 1) { $_SESSION["user"] = serialize(new User(mysql_fetch_assoc($result))); $_SESSION["login_time"] = time(); $_SESSION["logged_in"] = 1; return true; }else{ return false; } }
//Log the user out. Destroy the session variables. public function logout() { unset($_SESSION["user"]); unset($_SESSION["login_time"]); unset($_SESSION["logged_in"]); session_destroy(); } //Check to see if a username exists. //This is called during registration to make sure all user names are unique. public function checkUsernameExists($username) { $result = mysql_query("select id from users where username="$username""); if(mysql_num_rows($result) == 0) { return false; }else{ return true; }
}
//get a user //returns a User object. Takes the users id as an input public function get($id) { $db = new DB(); $result = $db->select("users", "id = $id"); return new User($result); } }
?>

Функция login()

Функция login() понятна по названию. Она берет аргументы пользователя $username и $password и проверяет их соответствие. Если все совпадает, создает объект User со всей информацией и сохраняет его в сессии. Обратите внимание, что мы только используем функцию PHP serialize(). Она создает сохраненный вариант объекта, который можно легко отменить с помощью unserialize(). Также время логина будет сохранено. Это может использоваться в дальнейшем для предоставления пользователям информации о длительности пребывания на сайте.

Вы также можете заметить, что мы выставляем $_SESSION["logged_in"] на 1. Это позволяет нам легко проверить на каждой странице залогинен ли пользователь. Достаточно проверить только эту переменную.

Функция logout()

Также простая функция. Функция PHP unset() очищает переменные в памяти, в то время как session_destroy() удалит сессию.

Функция checkUsernameExists()

Кто знает английский легко поймет функцию. Она просто запрашивает БД, использован ли подобный логин или нет.

Функция get()

Эта функция берет уникальный id пользователя и делает запрос к БД с помощью класса DB, а именно функции select(). Она возьмет ассоциативный массив с рядом информации о пользователе и создаст новый объект User, передавая массив конструктору.

Где можно это использовать? К примеру, если Вы создадите страницу, которая должна отображать специфические профили пользователей, Вам необходимо будет динамически брать эту информацию. Вот так Вы можете это сделать: (допустим УРЛ http://www.website.com/profile.php?userID=3)

//note: you will have to open up a database connection first. //see Part 1 for further information on doing so. //You"ll also have to make sure that you"ve included the class files.
$tools = new UserTools(); $user = $tools->get($_REQUEST["userID"]); echo "Username: ".$user->username.""; echo "Joined On: ".$user->joinDate."";

Легко! Правда?

Последний штрих серверной части: global.inc.php

global.inc.php необходим для каждой страницы сайта. Почему? Таким образом мы разместим все обычные операции, которые нам понадобятся на странице. К примеру, мы начнем session_start(). Соединение с БД также откроется.

require_once "classes/UserTools.class.php";
require_once "classes/DB.class.php";
//connect to the database $db = new DB(); $db->connect();
//initialize UserTools object $userTools = new UserTools(); //start the session
session_start();
//refresh session variables if logged in if(isset($_SESSION["logged_in"])) { $user = unserialize($_SESSION["user"]); $_SESSION["user"] = serialize($userTools->get($user->id)); } ?>

Что он делает?

Тут происходит несколько вещей. Прежде всего, мы открываем соединение с базой.

После соединения, мы начинаем функцию session_start(). Функция создает сессию или продолжает текущую, если пользователь уже залогинен. Поскольку наше приложение рассчитано на то, чтобы пользователи входили\выходили, эта функция обязательна на каждой странице.

Далее мы проверяем залогинен ли юзер. Если да - мы обновим $_SESSION["user"], чтобы отображать самую последнюю информацию о юзере. К примеру, если пользователь меняет свой емейл, в сессии будет храниться еще старый. Но с помощью авто обновления такого не случится.

На этом вторая часть подошла к концу! Завтра ожидайте заключительный урок по этой теме.

Всего наилучшего!

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

Что ж, сама по себе данная тема довольно грузная, и требует определённого времени на анализ и постанувку задачи.

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

Давайте с самого начала обсудим архитектуру модульной системы на выбранной нами псевдо-системе.

Все модули представлены ввиде подключаемых к главному документу (индекс-файлу) вставок. Запрос модуля происходит из строки запроса QUERY_STRING, и название подключаемого модуля передаётся в качестве аргумента act. В некотором месте индекса файла происходит изъятие и обработка данного параметра. После, если у пользователя достаточно прав для доступа к модулю в контексте чтения, происходит проверка существования указанного в строке запроса модуля, и если таковой существует, то происходит его подключение к индекс файлу.

Я не просто так упомянул о "контексте чтения", так как наша системе предполагает существование двух контекстов работы с системой, а именно - чтение и запись. При этом под чтением предполагается непосредственный доступ к модулю и к тем его частям, которые не предполагают внесение изменений в структуру данных в БД. Под записью же предполагается непосредственное внесение изменений в информацию, хранимую в базе данных.

Для воплощения данного механизма мы будет проверять значение переменной строки запроса `do`, которая обрабатывается в самом модуле и носит информацию о том, к какому разделу модуля необходимо предоставить доступ пользовалю.

Значение do буду фиксированными, данная переменная будет принимать следующие значения:

  • main - главная часть модуля (доступно в контексте чтения)
  • config - раздел настройки модуля (доступно в контексте записи)
  • create - произвести некоторые действия, по добавлению информации в БД (доступно в контексте записи)
  • delete - доступ к разделу, предоставляющему возможности удалить некоторую информацию, в контексте данного модуля (доступно в контексте записи)
  • edit - доступ к редактированию информации в контексте модуля (доступно в контексте записи)

В целом, этот список можно увеличить, при этом всё зависит лишь только от масштабов проекта и его потребностей в функционале.

Теперь непосредственно о модулях. Кроме физического существования некоторого модуля в контексте файловой системы проекта, модуль так же должен быть добавлен в особую таблицу БД, которая будет содержать информацию о всех существующих модулях в системе. Добавление и изменение данных данной таблицы, обычно, производится непосредственно в контексте модулей, а то есть во время их инсталяции в системе. Однако это уже углубление в принципы посмотроения расширяемых систем, о чём мы как-то в другой раз поговорим, и посему, мы ограничимся ручным обновлением и добавлением данных о модулях.

Так, запись о модуле системы будет содержать следующую информацию: английский идентификатор названия модуля, который будет идентичен значению переменной среды GET - act (относительно него будет производится непосредственно запрос модуля), русский идентификатор модуля, который будет использоватся в списке модулей.

Кроме модулей у нас будут ещё две таблицы, а именно таблица в которой будут хранится данные относительно профилей прав доступа и таблица с информацией о пользователях непосредственно.

Таблица профилей безопасности будет состоять всего из трёх полей - идентификатор профиля (числовое значение идентификатора записи), текстый идентификатор модуля (предназначенный для пользователей), а так же особым образом сформированная текстовая метка, содержащая информацию о правах пользователя, в контексте каждого из модулей.

Что ж, давайте рассмотрим эту особую структуру. Она будет следующей: [ module_indefier: + \: + \;] *

То есть идёт список из пар: имя модуля ":" права чтения "," права записи ";". При этом данная метка обновляется в момент внесения изменений о правах доступа пользователя к системе. Если в системе появляется информация о модуле, который не вошёл в данную метку, то стоит просто произвести процедуру редактирования, и данные сохранятся автоматически.

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

Я не буду добавлять ничего лишнего в неё, но лишь то, что будет использоватся в контексте темы данной статьи. Таблица пользователей будет содержать следующие поля: идентифицатор пользователя (числовой счётчик), логин, пароль (хеш оригинального пароля), профиль безопасности пользователя (идетификатор группы пользователя, относительно прав в системе), и всё. Мне кажется этой информации нам с вами вполне хватит, для реализации поставленной задачи, а уже все остальные надстройки я предоставляю возможность сделать самим.

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

Таблица `modules`:

CREATE TABLE `modules` (`id` bigint(20) NOT NULL auto_increment, `indefier` text collate utf8_unicode_ci NOT NULL, `title` text collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Таблица `secure_groups`:

CREATE TABLE `secure_groups` (`id` bigint(20) NOT NULL auto_increment, `title` text collate utf8_unicode_ci NOT NULL, `perms` text collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;

Таблица `users`

CREATE TABLE `users` (`id` bigint(20) NOT NULL auto_increment, `login` text collate utf8_unicode_ci NOT NULL, `passwd` text collate utf8_unicode_ci NOT NULL, `groupId` int(1) NOT NULL default "0", PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;

temp=array(); $this->temp["_result"]=0; $this->temp["_uid"]=explode("::",$_COOKIE["site_hash"]); $this->temp["_uid"]=$this->temp["_uid"]; $this->temp["_gid"]=$this->getUserSecurityAccess($this->temp["_uid"]); $this->temp["_conn_id"]=mysql_connect("host","user","passwd"); mysql_select_db("database"); $this->temp["_q1"]=mysql_query("SELECT perms" ."FROM `secure_groups`" ."WHERE id=".$this->temp["_gid"]); $this->temp["_access_stamp"]=mysql_fetch_assoc($this->temp["_q1"]); $this->temp["_access_stamp"]=$this->temp["_access_stamp"]["perms"]; $this->temp["_access_stamp"]=explode(";",$this->temp["_access_stamp"]); $this->temp["_access_stamp"]=array_slice($this->temp["_access_stamp"],0,-1); foreach($this->temp["_access_stamp"] as $this->temp["v"]){ $this->temp["_mod_access"]=explode(":",$this->temp["v"]); $this->temp["_mod_indefier"]=$this->temp["_mod_access"]; if($this->temp["_mod_indefier"]==$module){ $this->temp["_perms"]=explode(",",$this->temp["_mod_access"]); switch($act){ case "r": $this->temp["_result"]=($this->temp["_perms"]==1)? 1:0; break; case "w": $this->temp["_result"]=($this->temp["_perms"]==1)? 1:0; break; } break; } } mysql_close($conn_id); return $this->temp["_result"]; } } ?>

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

Функция secure::getUserId()

Используя данную функцию, мы подразумеваем, что во время авторизации пользователя в системе в переменной среде $_COOKIE была установлена переменная `site_hash`, состоящая из идентификатора пользователя в системе и хеша для проверки аутентичности его в системе. Функция просто изымает значение идентификатора, возращая его значение на выходе.

Функция secure::getUserSecurityAccess($id)

На выходе данная функция возвращает идентификатор профиля безопасности текущего пользователя в системе.

Функция secure::checkUserPermission($module,$act))

Производится запрос к БД, относительно прав пользователя на произведение действий чтения/записи в контексте переданного в качестве параметра модуля.

Осталось лишь описать процедуру формирования переменной в среде $_COOKIE, и тему статьи можно будет считать расскрытой.

Процедура авторизации будет выглядеть ввиде внесения личных данных пользователя (логин и пароль) в специальную форму, после отправки которой произойдёт обработка данных, переданных пользователем, по-методу функции checkAuthData(), и, в случае корректности данных, будет произведено сохранение данных о пользователе ввиде куки записи на период установленный пользователем, либо в отсутствии заданного значение на период по-умолчанию.

Для проверки аутентичности данных хранимых в переменной среде $_COOKIE, мы будем использовать функцию EatCookie(), которая будет производить валидацию данных, возвращая булевый результат проверки (истина - ложь).

Я не привожу форму для отправки, так как это не часть теории программирования, указав лишь идентификаторы полей.

  • `ulogin` - логин пользователя
  • `upasswd` - пароль пользователя
  • `stime` - время сессии, устанавливаемое пользователем (от 1 до 5 часов)
  • `auth` - имя кнопки отправки

Вот, в целом и всё. Осталось лишь пробовать, экспериментировать, ошибатся и находить решение, что я всецело и оставляю вам.

Надеюсь, что мы скоро встретимся, а для тех кто имеет ко мне вопрос в отношении статьи, да и не только - писать на [email protected], либо на [email protected].

С уважением Карпенко Кирилл, глава IT-отдела ИНПП.

1 year ago | 9.8K

В программированию, очень часто встречается задача, когда нужно обратиться к другому сайту через HTTP или HTTPS. В этой статье мы рассмотрим простой способ, как с помощью языка программирования PHP выполнить данную задачу.

Для чего обращаться с помощью PHP через HTTP или HTTPS к другому сайту?

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

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

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

Пример обращения к другому сайту с помощью PHP

В этом простом примере, мы будем использовать стандартную функцию PHP под названием file_get_contents().

В ответ от сервера VK, вы увидите следующую информацию:

{ - response: [ - { - id: 210700286, - first_name: "Lindsey", - last_name: "Stirling", - bdate: "21.9.1986" - } - ] }

где, мы получили Имя, Фамилию и дату рождения пользователя с ID 210700286.

Как теперь мы может с помощью PHP получить эту информацию и преобразовать ее в массив, для удобной дальнейшей работы?

С помощью языка программирования PHP и функции file_get_contents(), это сделать очень просто!

$user_id - это переменная, в которую вы записываете ID пользователя VK,

$info - в этой переменной мы сохраняем результат обращения к API сайта VK.COM

Имея массив с этой информацией, вы можете на вашем сайте, отображать интересных вам пользователей, для какой-либо цели, а также с помощью , вы можете красиво оформить вывод данной информации на вашем сайте.

Вывод

Как вы видите, с помощью PHP вы можете очень легко делать запросы к HTTP и HTTPS сайтам и мы рассмотрели лишь одну функцию языка программирования PHP с помощью которой можно получить данные из внешнего сайта.

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