Строим свою CMS на PHP и MySQL. Часть 2
В предыдущем уроке серии мы создали базу данных и конфигурационный файл для нашей простой CMS. Теперь создадим основной класс нашего приложения - Article.
В нашей CMS Article будет единственным классом PHP. Он будет обслуживать задачи сохранения статьи в базе данных и получения материалов для вывода на страницах проекта. Как только мы построим данный класс будет действительно легко создать другие скрипты для создания, обновления, вывода и удаления статей.
В нашей папке cms создаем каталог classes. В папке classes создаем новый файл с именем Article.php и копируем в него следующий код:
<?php
/**
* Класс для обработки статей
*/
class Article
{
// Свойства
/**
* @var int ID статей из базы данных
*/
public $id = null;
/**
* @var int Дата первой публикации статьи
*/
public $publicationDate = null;
/**
* @var string Полное название статьи
*/
public $title = null;
/**
* @var string Краткое описание статьи
*/
public $summary = null;
/**
* @var string HTML содержание статьи
*/
public $content = null;
/**
* Устанавливаем свойства с помощью значений в заданном массиве
*
* @param assoc Значения свойств
*/
public function __construct( $data=array() ) {
if ( isset( $data['id'] ) ) $this->id = (int) $data['id'];
if ( isset( $data['publicationDate'] ) ) $this->publicationDate = (int) $data['publicationDate'];
if ( isset( $data['title'] ) ) $this->title = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['title'] );
if ( isset( $data['summary'] ) ) $this->summary = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['summary'] );
if ( isset( $data['content'] ) ) $this->content = $data['content'];
}
/**
* Устанавливаем свойств с помощью значений формы редактирования записи в заданном массиве
*
* @param assoc Значения записи формы
*/
public function storeFormValues ( $params ) {
// Сохраняем все параметры
$this->__construct( $params );
// Разбираем и сохраняем дату публикации
if ( isset($params['publicationDate']) ) {
$publicationDate = explode ( '-', $params['publicationDate'] );
if ( count($publicationDate) == 3 ) {
list ( $y, $m, $d ) = $publicationDate;
$this->publicationDate = mktime ( 0, 0, 0, $m, $d, $y );
}
}
}
/**
* Возвращаем объект статьи соответствующий заданному ID статьи
*
* @param int ID статьи
* @return Article|false Объект статьи или false, если запись не найдена или возникли проблемы
*/
public static function getById( $id ) {
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles WHERE id = :id";
$st = $conn->prepare( $sql );
$st->bindValue( ":id", $id, PDO::PARAM_INT );
$st->execute();
$row = $st->fetch();
$conn = null;
if ( $row ) return new Article( $row );
}
/**
* Возвращает все (или диапазон) объектов статей в базе данных
*
* @param int Optional Количество строк (по умолчанию все)
* @param string Optional Столбец по которому производится сортировка статей (по умолчанию "publicationDate DESC")
* @return Array|false Двух элементный массив: results => массив, список объектов статей; totalRows => общее количество статей
*/
public static function getList( $numRows=1000000, $order="publicationDate DESC" ) {
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles
ORDER BY " . mysql_escape_string($order) . " LIMIT :numRows";
$st = $conn->prepare( $sql );
$st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
$st->execute();
$list = array();
while ( $row = $st->fetch() ) {
$article = new Article( $row );
$list[] = $article;
}
// Получаем общее количество статей, которые соответствуют критерию
$sql = "SELECT FOUND_ROWS() AS totalRows";
$totalRows = $conn->query( $sql )->fetch();
$conn = null;
return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
}
/**
* Вставляем текущий объект статьи в базу данных, устанавливаем его свойства.
*/
public function insert() {
// Есть у объекта статьи ID?
if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR );
// Вставляем статью
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles ( publicationDate, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), :title, :summary, :content )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );
$st->bindValue( ":title", $this->title, PDO::PARAM_STR );
$st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );
$st->bindValue( ":content", $this->content, PDO::PARAM_STR );
$st->execute();
$this->id = $conn->lastInsertId();
$conn = null;
}
/**
* Обновляем текущий объект статьи в базе данных
*/
public function update() {
// Есть ли у объекта статьи ID?
if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Attempt to update an Article object that does not have its ID property set.", E_USER_ERROR );
// Обновляем статью
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "UPDATE articles SET publicationDate=FROM_UNIXTIME(:publicationDate), title=:title, summary=:summary, content=:content WHERE id = :id";
$st = $conn->prepare ( $sql );
$st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );
$st->bindValue( ":title", $this->title, PDO::PARAM_STR );
$st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );
$st->bindValue( ":content", $this->content, PDO::PARAM_STR );
$st->bindValue( ":id", $this->id, PDO::PARAM_INT );
$st->execute();
$conn = null;
}
/**
* Удаляем текущий объект статьи из базы данных
*/
public function delete() {
// Есть ли у объекта статьи ID?
if ( is_null( $this->id ) ) trigger_error ( "Article::delete(): Attempt to delete an Article object that does not have its ID property set.", E_USER_ERROR );
// Удаляем статью
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$st = $conn->prepare ( "DELETE FROM articles WHERE id = :id LIMIT 1" );
$st->bindValue( ":id", $this->id, PDO::PARAM_INT );
$st->execute();
$conn = null;
}
}
?>
Файл получается достаточно длинным, но код очень простой. Разберем его подробно:
1. Определение класса и его свойства
Сначала определим класс Article:
Все, что следует за данным строками до закрывающей фигурной скобки в конце файла содержит код нашего класса Article.
После определения класса мы объявляем свойства класса : $id, $publicationDate и так далее. Каждый объект Article, который мы создаем, будет хранить данные в объявленных свойствах. Обратите внимание, что имена свойств соответствуют именам полей в таблице articles.
Технически, такой тип класса, который содержит свойства соответствующие непосредственно полям базы данных и методы для хранения и получения записей, соответствует шаблону объектно-ориентированного проектирования, известному как active record.
2. Конструктор
Затем мы создаем методы класса. Это функции, которые привязаны к классу и к объекту, создаваемому из класса. Наш основной код вызывает методы для манипулирования данными в объекте Article.
Первый метод, __construct(), является конструктором. Это специальный метод, который автоматически вызывается системой PHP каждый раз, когда создается новый объект Article. Наш конструктор получает необязательный массив $data, в котором содержатся данные для свойств нового объекта. Затем мы присваиваем данные свойствам в теле конструктора. Таким образом, получается удобный способ для создания и инициализации объекта в одно действие.
$this->propertyName означает: "Свойство объекта this с именем "$propertyName".
Обратите внимание, что метод фильтрует данные, прежде чем присвоить их свойствам. Свойства id и publicationDate приводятся к типу int с помощью (int), так данные значения должны быть типа int. Свойства title и summary фильтруются с помощью регулярных выражений, так как в них допускает наличие символов из определенного набора. С точки зрения безопасности фильтрация данных ввода - отличная практика. Пропускаем только допустимые значения и символы.
Однако, мы не фильтруем свойство content. Почему? Вероятно, администратор захочет использовать более широкий диапазон символов в содержании статьи - например, разметку HTML. Если мы ограничим диапазон доступных символов в содержании, то снизим полезность нашей системы для администратора.
Обычно, такие места могут оказаться дырой в системе безопасности, так как пользователь может вставить вредный код JavaScript или материалы с ошибками в содержание статьи. Однако, так как мы полагаем. что единственной персоной, которой доступно редактирование содержание, будет администратор системы, располагающий безграничным доверием, то вопрос с уязвимостью содержания остается за рамками нашего внимания. Если вы имеете дело с генерируем пользователями содержанием, например, комментариями или записями форума, то следует быть более осторожным и допускать только "безопасный" код HTML к использованию. Отличным инструментом для решения таких задач является HTML Purifier, который анализирует ввод кода HTML и удаляет все потенциальные угрозы.
Безопасность кода PHP выходит за рамки наших уроков. Вам следует посвятить определенное время для изучения данного вопроса.
3. storeFormValues()
Следующий метод storeFormValues()похож на конструктор в том, что он сохраняет полученный массив данных в свойствах объекта. Основное отличие заключается в том, что storeFormValues() может обрабатывать данные в формате, который используется в формах New Article (Новая статья) и Edit Article (Редактировать статью) (мы создадим их позже). В частности, он может обрабатывать дату публикации в формате YYYY-MM-DD, конвертировать ее в формат времени UNIX, который отлично подходит для хранения в объекте.
Формат времени UNIX представляет собой целое значение, которое содержит количество секунд от полуночи 1 января 1970 до искомой даты. Датой в таком формате легко оперировать, и ее удобно хранить.
Назначение данного метода - облегчить реализацию скрипта для хранения дат, вводимых в формах.
Все члены (то есть свойства и методы) нашего класса Article имеют ключевое слово public перед определением, что означает доступность кода вне класса. Также можно создавать частные члены (директива private) (их можно использовать только в классе) и защищенные члены (директива protected) (которые можно использовать в классе и его подклассах).
4. getById()
Теперь перейдем к методам, реализующим доступ к базе данных MySQL. Первый из них - getById(). Он принимает в качестве аргумента ID статьи ($id) и возвращает запись с указанным ID из таблицы articles, сохраняя данные в новом объекте Article.
Обычно, когда вы вызываете метод, сначала нужно создать объект, а затем вызвать метод, принадлежащий объекту. Но, так как getById() возвращает новый объект Article, будет полезно вызывать его напрямую, а не через существующий объект. Иначе придется создавать новый объект-заглушку каждый раз, когда нужно вызвать вызвать метод и получить статью.
Для разрешения вызова метода без объекта мы добавляем декларацию static к определению метода. Таким образом разрешается вызов метода непосредственно без определения объекта.
public static function getById( $id ) {
Метод использует PDO для соединения с базой данных, получает запись статьи с помощью запроса SQL SELECT и сохраняет данные в новом объекте Article, который возвращается в вызывающий код. PDO — PHP Data Objects —объектно-ориентированная библиотека, встроенная в PHP, которая облегчает связь скриптов PHP с базами данных.
Разберем метод подробнее:
-
Соединение с базой данных
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
Здесь выполняется соединение с базой данных MySQL с помощью данных из файла
config.php. Дескриптор соединения сохраняется в переменной$conn. Данный дескриптор используется в остальном коде для обмена данных с базой. -
Получаем запись статьи
$sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles WHERE id = :id"; $st = $conn->prepare( $sql ); $st->bindValue( ":id", $id, PDO::PARAM_INT ); $st->execute(); $row = $st->fetch();
Выражение
SELECTвозвращает все поля (*) из записи в таблицеarticles, которые соответствуют заданному полюid. Значение поляpublicationDateвозвращается в формате времени UNIX, вместо формата для дат MySQL, что упрощает процесс сохранения в нашем объекте.Вместо того, чтобы помещать наш параметр
$idнепосредственно в строкуSELECT, что увеличивает риск нарушения системы безопасности, мы используем:id. Такой параметр известен как placeholder (указатель места размещения). Далее мы вызываем метод PDO для привязывания значение$idк указателю места размещения.Сразу после сохранения выражения
SELECTв строке, мы подготавливаем его с помощью функции$conn->prepare(), сохраняя полученный дескриптор в переменной$st.Подготовка выражения используется для работы со многими базами данных. Она позволяет выполнять запросы быстрее и безопаснее.
Затем мы привязываем значение переменной
$id( ID нужной статьи) к указателю места размещения:idс помощью вызова методаbindValue().И вызываем метод
execute()для выполнения запроса. После чего используем методfetch()для перемещения полученной записи в ассоциированный массив с именами полей и соответствующими значениями, который хранится в переменной$row. -
Закрываем соединение
Так ка нам больше не нужно соединение, мы закрываем его, присваивая значение
nullпеременной$conn. Закрывать соединение с базой данных как можно быстрее является хорошей практикой для освобождения памяти на сервере. -
Возвращаем объект
Articleif ( $row ) return new Article( $row ); }
Последним действием в нашем методе является создание объекта
Article, который будет содержать запись из базы данных, и возвращение его вызывающему коду. Сначала проверяем наличие данных в переменной$rowпосле вызова методаfetch(). Если данные есть, создаем новый объектArticleпередавая переменную ему$row. Будет вызван конструктор класса, который наполнит объект данными из массива$row. Затем возвращаем готовый объект и работа метода завершена.
5. getList()
Следующий метод getList() во многом похож на метод getById(). Основное отличие заключается в том, что метод getList() возвращает несколько статей сразу. Его используют, когда нужно вывести список статей для пользователя или администратора.
getList() принимает 2 аргумента:
$numRows- Максимальное количество получаемых статей. По умолчанию установлено значение 1,000,000 (то есть, практически все статьи). Данный параметр позволяет нам получать только первые 5 статей для главной страницы.
$order- Порядок сортировки получаемых статей. По умолчанию используется параметр
"publicationDate DESC", который означает "сортировка по дате публикации, новые статьи первые".
Большая часть кода метода похожа на код метода getById(). Посмотрим на несколько строк:
$sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles
ORDER BY " . mysql_escape_string($order) . " LIMIT :numRows";
Здесь запрос немного сложнее. Обратите внимание, что здесь не используется выражение WHERE, так как мы хотим получить все статьи, а не одну с заданным ID.
Также добавлено выражение ORDER BY для сортировки возвращаемых записей в определенном порядке. Используется выражение LIMIT с параметром $numRows (как указатель места размещения) для ограничения количества получаемых записей.
Специальное значение MySQL SQL_CALC_FOUND_ROWS указывает базе данных, что нужно вернуть действительное количество возвращаемых записей. Такая информация полезна для информирования пользователя и организации других функций, например, постраничного вывода списка.
Вместо передачи значения переменной $order в запрос через указатель места размещения, мы передаем его прямо в строку запроса, вызывая функцию mysql_escape_string(), чтобы отбросить любые специальные символы (для безопасности). Если использовать указатель места размещения, то PDO поместит кавычки (') вокруг строки (например, ORDER BY 'publicationDate DESC'), что является ошибкой синтаксиса.
$list = array();
while ( $row = $st->fetch() ) {
$article = new Article( $row );
$list[] = $article;
}
Так как мы возвращаем несколько строк, нужно создать массив $list для размещения соответствующих объектов Article. Затем используем цикл while для получения следующей строки через fetch(), создаем новый объект Article, сохраняем строку в объекте и добавляем объект к массиву $list. Когда строк не останется, метод fetch() вернет false, и цикл остановится.
// Теперь получаем общее число статей, которые соответствуют критерию $sql = "SELECT FOUND_ROWS() AS totalRows"; $totalRows = $conn->query( $sql )->fetch(); $conn = null; return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
В завершении мы выполняем запрос, который использует функцию MySQL FOUND_ROWS() для получения количества возвращаемых строк, вычисленного в предыдущей команде SQL_CALC_FOUND_ROWS. В этот раз используем метод PDO query(), который позволяет быстро выполнить запрос, если нет указателей места замещения. Мы вызываем метод fetch() для получения результата. Затем возвращаем оба значения - список объектов Article ($list) и общее количество строк - как ассоциированный массив.
6. insert()
Оставшиеся методы в нашем классе Article работают с добавлением, изменением и удалением записей статей в базе данных.
insert() добавляет новую статью в таблицу articles, используя значения из текущего объекта Article:
- Сначала метод проверяет, что объект не имеет установленного свойства
$id. Если у объекта есть ID, то, вероятно, статья уже имеется в базе данных и ее добавлять не нужно. - Затем метод выполняет запрос SQL
INSERTдля вставки записи в таблицуarticles, используя указатели места замещения для передачи значений свойств в базу данных. Обратите внимание, что мы используем функцию MySQLFROM_UNIXTIME()для конвертации даты публикации в формат MySQL. - После выполнения запроса, метод возвращает ID новой статьи с помощью функции PDO
lastInsertId()и сохраняет значение в свойстве$id. Мы установили в таблицеarticlesдля поляidсвойствоauto_increment, поэтому MySQL генерирует уникальное значение ID для каждой новой записи.
Обратите внимание, что мы используем PDO::PARAM_INT при привязке целых значений к указателям места замещения, и PDO::PARAM_STR при привязке строк. Таким образом, PDO может правильно обрабатывать значения.
7. update ()
Данный метод похож на метод insert(), за исключением того, что здесь происходит обновление записи в базе данных вместо создания новой записи.
Сначала проверяем наличие ID у объекта, так как обновить можно только запись с известным ID. Затем используем выражение SQL UPDATE для обновления полей записи. Обратите внимание на передачу ID объекта в выражение UPDATE, так как мы знаем, какую запись надо обновить.
8. delete ()
Метод delete() использует выражение SQL DELETE для удаления из таблицы articles статьи, которая хранится в в объекте. Для идентификации записи задействуем свойство $id объекта. Для безопасности мы добавили LIMIT 1 к запросу, чтобы ограничиться удалением только одной записи.
В следующем уроке мы созадаим скрипты для клиентской и серверной части нашего приложения.
Источник: http://feedproxy.google.com/~r/ruseller/CdHX/~3/aTByynLrhoY/lessons.php
|
В предыдущем уроке серии мы создали базу данных и конфигурационный файл для нашей простой CMS. Теперь создадим основной класс нашего приложения - Article.В нашей CMS Article будет единственным |
РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2025-12-02 » Когда ошибка молчит: как бессмысленные сообщения ломают пользовательский опыт
- 2025-12-02 » 9 лучших бесплатных фотостоков
- 2025-12-02 » UTM-метки: ключевой инструмент аналитики для маркетолога
- 2025-12-02 » ПромоСтраницы Яндекса: Что такое и для чего служит
- 2025-12-02 » Метатеги для сайта: исчерпывающее руководство по Title, Description, Canonical, Robots и другим тегам
- 2025-11-26 » Оценка эффективности контента: превращаем информационный балласт в рабочий актив
- 2025-11-26 » 10 причин высокого показателя отказов на сайте
- 2025-11-26 » Когда и зачем обновлять структуру сайта
- 2025-11-26 » Скрытые демотиваторы: как мелочи разрушают эффективность команды
- 2025-11-26 » Зачем запускать MVP и как сделать это грамотно?
- 2025-11-20 » Половина российских компаний сократит расходы на транспорт и маркетинг в 2026 году
- 2025-11-20 » Перенос сайта с большим количеством ссылок
- 2025-11-20 » Перелинковка сайта: Что такое и как ее использовать
- 2025-11-20 » Критерии выбора SEO-специалиста и подрядчика для продвижения сайта
- 2025-11-20 » Применение искусственного интеллекта в рекламных агентствах: комплексное исследование трендов 2025 года
- 2025-11-19 » Геозапросы по-новому: как покорить локальное SEO с помощью ИИ
- 2025-11-14 » Консалтинг: сущность и ключевые направления
- 2025-11-14 » Онлайн-формы: универсальный инструмент для сбора обратной связи
- 2025-11-14 » Факторы конверсии органического трафика
- 2025-11-14 » Планирование рекламного бюджета: самостоятельный подход
- 2025-11-14 » Авторизация на сайте: как выбрать решение для удержания клиентов и сохранения продаж
- 2025-11-13 » Эффективные методы стимулирования клиентов к оставлению положительных отзывов
- 2025-11-13 » Налоговая реформа — 2026: грядущие изменения для предпринимателей
- 2025-11-13 » Альтернативы мессенджерам: что выбрать вместо Telegram и WhatsApp
- 2025-11-13 » Маркировка рекламы для начинающих: полное руководство по требованиям ЕРИР
- 2025-11-13 » ИИ не отберет вашу работу — её займет специалист, владеющий искусственным интеллектом
- 2025-10-29 » Как оценить эффективность работы SEO-специалиста: практическое руководство для маркетологов и владельцев бизнеса
- 2025-10-29 » Киберспорт как маркетинговый инструмент: стратегии привлечения геймеров
- 2025-10-29 » Как говорить с аудиторией о сложном
- 2025-10-29 » Что такое доказательства с нулевым разглашением (ZKP) и их роль в блокчейне
Мудрость приносит следующие три плода: дар хорошо мыслить, хорошо говорить и хорошо поступать Демокрит - (около 460 до н.э.- около 360 до н.э.) - древнегреческий философ |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.


Мы создаем практически любые сайты от продающих страниц до сложных, высоконагруженных и нестандартных веб приложений! Наши сайты это надежные маркетинговые инструменты для успеха Вашего бизнеса и увеличения вашей прибыли! Мы делаем красивые и максимально эффектные сайты по доступным ценам уже много лет!
Комплексный подход это не просто продвижение сайта, это целый комплекс мероприятий, который определяется целями и задачами поставленными перед сайтом и организацией, которая за этим стоит. Время однобоких методов в продвижении сайтов уже прошло, конкуренция слишком высока, чтобы была возможность расслабиться и получать \ удерживать клиентов из Интернета, просто сделав сайт и не занимаясь им...
Мы оказываем полный комплекс услуг по сопровождению сайта: информационному и техническому обслуживанию и развитию Интернет сайтов.
Контекстная реклама - это эффективный инструмент в интернет маркетинге, целью которого является увеличение продаж. Главный плюс контекстной рекламы заключается в том, что она работает избирательно.