index

Перейдите к pset7/public и откройте index.php (в CS50 IDE или gedit «Виртуальной лаборатории»). Помните, index.php — это файл, который обычно загружается при открытии адреса наподобие http://pset7/. Похоже, в этом файле не так уж и много PHP-кода! И в нем вообще нет HTML. Зато index.php подсоединяет config.php (он расположен в директории includes в родительской директории index.php). Далее, index.php вызывает render (функцию, которая реализована в файле helpers.php или functions.php, который можно найти в папке includes), чтобы зарендерить (то есть вывести) шаблон portfolio.php (который находится в директории views или templates, которая является в родительской директории index.php).

Подготовка к практическому заданию (продолжение) - 1

Похоже, что index.php рассматривается как «контроллер», то есть его предназначение — контролировать поведение вашего сайта, когда пользователь посещает http: // pset7 / (или http: //pset7/index.php). Вам придется добавить в этот файл немного PHP-кода, чтобы он выводил не только заголовок страницы. Давайте посмотрим на portfolio.php, шаблон, который этот контроллер, собственно, выводит.

portfolio

В «Виртуальной лаборатории» перейдите к ~/vhosts/pset7/templates и откройте portfolio.php в gedit.

В CS50 IDE перейдите в ~/workspace/pset7/views и найдите там portfolio.php.

Подготовка к практическому заданию (продолжение) - 2

Ага, здесь есть немного HTML. Впрочем, не слишком много.

config

Теперь перейдите к ~/vhosts/pset7/includes (в «Лаборатории) или ~/workspace/pset7/includes (В CS50 IDE) и откройте config.php.

Помните, config.php подключался к index.php, вы могли видеть это выше. Обратите внимание, что сначала config.php включает вывод всех ошибок (а также замечаний и уведомлений, которые менее критичны, чем ошибки). Так что вы сможете заметить любые синтаксические (и другие) ошибки в своем коде. Также обратите внимание, что самому config.php требуются два других файла: helpers.php и CS50.php (в «Виртуальной лаборатории» — constants.php и functions.php).

Подготовка к практическому заданию (продолжение) - 3

Затем config.php вызывает session_start для включения $ _SESSION, «суперглобальной» переменной, с помощью которой мы запомним, что пользователь залогинен. И хотя HTTP протокол не сохраняет «состояние», когда браузеры отсоединяются от сервера, как только они загрузили все страницы, «куки» (cookies) позволяют браузерам напоминать кто они, а точнее, кто вы во время последовательных запросов страниц. PHP использует «сессионные куки» (session cookies). Они лежат в $ _SESSION, ассоциативном массиве, где можно хранить любые данные, к которым вы планируете получать доступ во время визита пользователя на сайт. В тот момент, когда пользователь заканчивает свою «сессию» (то есть визит на сайт), закрывая свой браузер, содержание $ _SE SSION теряется для этого конкретного пользователя, ведь во время следующего визита этот пользователь получает новое куки. Между тем, config.php перенаправляет пользователя на login.php в любой момент, когда тот пытается открыть любую страницу отличную от login.php, logout.php и register.php, предполагая, что $ _SESSION [ "id"] не установлен. Другими словами, config.php требует от пользователей залогиниться, если они этого еще не сделали (и если они не зашли на одну из тех трех страниц).

CS50 IDE: helpers

Внимание! Если вы выполняете практические задания в «Виртуальной лаборатории CS50», смело пропускайте этот параграф.

Хорошо, теперь откройте helpers.php. Похоже, helpers.php определяет массу других функций, первая из которых — apologize, которую вы вызываете каждый раз, когда вам нужно сказать пользователю, что он совершил ошибку. Далее определяется dump, которую вы вольны вызывать во время работы над сайтом всякий раз, когда хотите увидеть содержимое (возможно, рекурсивно) некоторой переменной. Эта функция нужна только для диагностики. Далее в файле идет logout, функция, которая выводит пользователя с сайта, уничтожая его сессию.

Далее, lookup — функция, которая спрашивает Yahoo Finance для получения цен акций и других данных. Об этом чуть дальше. Затем идет redirect, функция, которая позволяет перенаправить пользователя с одной URL на другой. И, наконец, render, функция, которую вызывает index.php, чтобы вывести (зарендерить) portfolio.php. Далее функция «вытягивает» эти значения в локальное пространство имен (т.е. ключ «foo» со значением «bar» в массиве $ values становится локальной переменной $ foo со значением "bar"). И дальше она подключает header.php, и затем $view, и еще footer.php, выводя таким образом все три.

«Виртуальная лаборатория CS50»: functions

Внимание! Если вы выполняете практические задания в CS50 IDE, смело пропускайте этот параграф.

Хорошо, теперь откройте functions.php в gedit. Похоже, что functions.php требует constants.php, но о нём чуть позднее. Также functions.php определяет массу функций, первая из которых — apologize, которую вы вызываете каждый раз, когда вам нужно сообщить пользователю, что он совершил ошибку. Далее определяется dump, которую вы можете вызвать во время работы над сайтом каждый раз, когда хотите увидеть содержимое (возможно, рекурсивно) некоторой переменной. Эта функция нужна только для диагностики. Далее в файле идет logout — функция, которая выводит пользователя на сайте, уничтожая его сессию. Потом — lookup, функция, которая спрашивает Yahoo Finance для получения цен акций и других данных. Об этом чуть дальше. Затем идет query, эта функция вызывает SQL-запрос, а затем возвращает набор строк из базы, если такие вообще есть. Под ней — redirect, функция, которая позволяет перенаправить пользователя с одной URL на другой. Наконец, render. Эту функцию вызывает index.php, чтобы вывести (зарендерить) portfolio.php. После этого функция «вытягивает» эти значения в локальное пространство имен (т.е. ключ «foo» со значением «bar» в массиве $ values становится локальной переменной $ foo со значением «bar»). И дальше она подключает header.php, и затем $ template, и еще footer.php, выводя таким образом все три.

header, footer

Перейдите в pset7/views (CS50 IDE) или pset7/templates (в «Виртуальной лаборатории») и откройте header.php и footer.php. Там будет ещё больше HTML!

Благодаря рендеру содержимое этих файлов будет добавлено соответственно наверху и внизу всех ваших страниц. Так что все страницы будут иметь доступ к библиотеке Twitter’s Bootstrap и скриптовым тегам. И каждая страница будет иметь минимум четыре элемента div, три из которых имеют уникальные ID (top, middle и bottom) ради упрощения добавления стилей с помощью CSS.

Оцените, как интересно header.php выводит $ title с условием, если он определен.

Подготовка к практическому заданию (продолжение) - 4

Помните, следующую строку в index.php:

render (“portfolio.php” [ “title” => “Portfolio”]);

Это потому, что render вызывает extract для этого второго аргумента (массива), перед вызовом header.php. И так, в конце концов, header.php получает доступ к переменной $ title. Неплохо, правда? Вы можете передать в шаблон еще больше значений просто перечисляя их ключ / значение через запятую, как в примере ниже:

render ( "portfolio.php" [ "cash" => 10000.00, "title" => "Portfolio"]);
login

Снова переходите в pset7/public и откройте login.php, другой контроллер. Этот контроллер несколько сложнее, чем index.php, поскольку он отвечает за аутентификацию пользователей.

Подготовка к практическому заданию (продолжение) - 5

Пройдитесь внимательно по коду, обратите внимание, каким образом он делает запросы к базе данных MySQL с помощью функции query. Эта функция (которую мы написали) упрощает использование PDO (PHP Data Objects, объектов данных PHP) — библиотеки, с помощью которой вы можете делать запросы к базе данных MySQL (и других). Как printf, функция query принимает нуль или более аргументов: строка SQL и за ней через запятую список параметров (хотя они могут и вовсе отсутствовать). И там, где printf использует %i, %s, и другие плейсхолдеры, функция query использует знаки вопроса (?), независимо от типа значений.

Так что результатом выполнения

CS50::query("SELECT * FROM users WHERE username = ?", $_POST["username"]);

В login.php будет замена знака вопроса именем пользователя, которое было передано через POST в форме HTML. Функция также гарантирует, что все эти значения плейсхолдеров правильно обрабатываются слешами, чтобы код невозможно было взломать с помощью SQL-инъекций.

Например, предположим, что President Skroob пытается войти на C$ 50 Finance, введя имя пользователя и пароль. Эта строка кода в конце концов вызовет следующий SQL запрос:

SELECT * FROM users WHERE username = 'skroob"

Здесь важно отметить, что PHP — язык со слабой типизацией, поэтому такие функции, как query, могут возвращать значения разных типов.
Если запрос передается оператором SELECT, он возвращает массив с 0 или более строками. Если запрос передается операторами DELETE, INSERT или UPDATE, он будет возвращать неотрицательное целое число, которое представляет число удаленных, вставленных или обновленных строк соответственно.

Посмотрите на код ниже. Он может оказаться полезным, когда придёт время реализовывать register.php. Обратите внимание на то, как работает IGNORE: этот оператор гарантирует, что если имя пользователя уже существует, будет возвращён нуль (из-за ограничения UNIQUE этого столбца, per pset7.sql). Без IGNORE, это состояние может вызвать ошибку.

$rows = CS50::query("INSERT IGNORE INTO users (username, hash, cash) VALUES(?, ?, 10000.0000)",
$_POST["username"], password_hash($_POST["password"], PASSWORD_DEFAULT));
if ($rows !== 1)
{
    // the INSERT failed, presumably because username already existed
}

В любом случае обратите внимание, что login.php проверяет пароль пользователя с помощью password_verify. См. Http://php.net/manual/en/function.password-verify.php для получения дополнительной информации.

Также обратите внимание на то, login.php «помнит», что пользователь вошел в систему, сохраняя свой уникальный идентификатор внутри $ _SESSION. Как и прежде, этот контроллер не содержит HTML. Скорее, он вызывает apologize или рендерит login_form.php по мере необходимости. Фактически, открывает login_form.php в ~ / workspace / pset7 / views. Большая часть этого файла состоит из HTML, стилизованного посредством некоторых классов CSS начальной загрузки. Только обратите внимание на то, как HTML-форма отправляет POST-запрос к login.php. Ради полноты картины, загляните в apology.php, пока вы находитесь в этом каталоге. А также загляните в logout.php в pset7/public, чтобы увидеть, что происходит, когда пользователь выходит из системы.

styles

Отлично, теперь перейдите в pset7/public/css и откройте styles.css. Обратите внимание, этот файл уже содержит несколько «селекторов», поэтому вам не нужно добавлять атрибуты стилей к элементам, соответствующим этим селекторам.

Для решения этого практического задания вам не понадобится становиться мастером CSS, но помните, вам нужно иметь более одного div-элемента на странице, атрибут id которого имеет значение top. Или более одного div на странице, значение id которого = middle. Или же более одного элемента div на странице, атрибут id которого = bottom. При этом id должен быть уникальным. В любом случае, вы свободны модифицировать styles.css как вам заблагорассудится.

Мы также советуем вам взглянуть на ~/vhosts/pset7/public/js, там собраны файлы с JavaScript. Кстати, на JavaScript для решения задания также писать не нужно. Эти файлы здесь только для того, если вы захотите немного поэкспериментировать.

Советуем немного отдохнуть и перехватить чего-нибудь=).

users

Хорошо, давайте теперь обсудим базу данных, которую вы ранее создали (запуская инструкции в pset7.sql во вкладке SQL phpMyAdmin).
Снова перейдите на https://ide50-username.cs50.io/phpmyadmin/ в CS50 IDE или на страничку http: //pset7/phpmyadmin/ в Chrome внутри «Виртуальной лаборатории».

Подготовка к практическому заданию (продолжение) - 6

Залогиньтесь, если потребуется. После этого вы окажетесь на главной странице phpMyAdmin. В её левом верхнем углу вы увидите базу данных pset7, в ней есть таблица users (убедитесь в этом, кликнув на +). А теперь кликните на имя этой таблицы, чтобы посмотреть её содержимое. Кликните на имя этой таблицы, чтобы увидеть ее содержимое. Ага, знакомые ребята! Итак, имеем имя пользователя President Skroob и хэш его пароля (такой же, как и код его шкафчика в раздевалке)!

Теперь кликните на вкладку Structure. И снова всё знакомо! Вспомните, что login.php генерирует запросы такого плана:

SELECT id FROM users WHERE username = 'skroob"

С phpMyAdmin становится понятно, что эта таблица пользователей содержит три поля: id (типа INT и UNSIGNED) вместе с username и hash (обе относятся к типу VARCHAR). Похоже, что ни одно из полей не может быть NULL, а их максимальная длина равна 255. Отличное свойство поля id заключается в том, что оно является AUTO_INCREMENT: когда добавляете нового пользователя в базу, не нужно указывать значение для id, пользователю будет предписано следующее доступное значение INT. Наконец, если вы кликните Indexes (над Information), вы увидите, что в этой таблице первичный ключ (PRIMARY key) — это id, поэтому, как следствие, не может быть двух пользователей с одинаковыми ID. Вспомните, что первичный ключ — это поле, которое не может содержать повторных значений. Конечно, username также должно быть уникальным, поэтому мы определили его таким (с помощью дополнительного Yes под Unique). Для уверенности мы могли бы сделать поле username первичным ключом таблицы. Однако эффективнее использовать целые значения, наподобие id. Эти поля называются «индексами», потому что первичный ключ и другие уникальные поля используются базой данных для построения «индексов» — структур данных, применяемых для быстрого поиска по этим полям.

Хорошо, давайте дадим каждому из ваших пользователей немного налички. Если вы всё ещё не закрыли вкладку Structure phpMyAdmin, вы видите форму, с помощью которой можно добавлять новые колонки. Отметьте с помощью радиокнопки поле After, выберите hash раскрывающемся меню, как показано ниже, и кликните Go.

Подготовка к практическому заданию (продолжение) - 7

В новой форме определите поле с названием cash с типом DECIMAL и длиной, равной 65,4, с дефолтным значением 0.0000 и с атрибутом UNSIGNED, как показано ниже, и затем кликните Save.

Подготовка к практическому заданию (продолжение) - 8

Если посмотрите документацию по MySQL, то обнаружите, что тип данных DECIMAL используется для сохранения точных числовых данных. Длина 65,4 для DECIMAL означает, что значение для cash не могут быть длиннее 65 разрядов, и только 4 из них могут располагаться справа от запятой.

Теперь перейдите на вкладку Browse и вручную подарите каждому по $ 10,000.00. Теоретически, мы могли бы определить cash так, чтобы его значение по умолчанию составляло 10000.000, но в целом стоит размещать такие вещи в коде, а не в базе данных, поскольку так потом будет проще их исправлять.

Самый простой способ — кликнуть на Check All, дальше кликнуть Change справа от иконки карандаша. На странице, которая появится, измените 0.0000 на 10000.0000 для каждого пользователя, а дальше кликните Go. Ребята будут рады!