PHPFog — это относительно новый провайдер облачного хостинга, специально разработанный для приложений PHP. Их миссия — «меньше управления, больше кода», и вся платформа сосредоточена вокруг наиболее используемых и надежных инструментов PHP. В качестве примера я попытался начать новый блог на WordPress по бесплатному плану, и это заняло всего 3 минуты! Также процесс установки и обновления плагинов и тем происходит мгновенно!
В этом уроке я создам простое приложение для формы подписки, используя две из поддерживаемых PHPFog фреймворков: Slim для части PHP и Twitter Bootstrap для части CSS. В качестве бонуса приложение воспользуется новыми адаптивными функциями платформы Bootstrap 2 и будет доступно из коробки с настольных ПК, планшетов и смартфонов.
Ключевые особенности платформы
Чем PHFog отличается от других провайдеров?
Во-первых, платформа PHPFog основана на хорошо известных и надежных технологиях с открытым исходным кодом. HTTP-запросы сначала фильтруются прокси-сервером кэша Varnish, а затем передаются через балансировщик нагрузки Nginx, который распределяет рабочую нагрузку между несколькими серверами приложений. Эти серверы являются выделенными машинами Linux, работающими под управлением Apache с mod_php и расширением APC (Advanced PHP Cache). Хранилище базы данных управляется MySQL с использованием масштабируемой установки «ведущий-ведомый».
Во-вторых, платформа предназначена как для разработчиков, так и для не разработчиков. Во время настройки приложения вы можете начать с пустого настраиваемого приложения PHP, с одной из предлагаемых платформ PHP (включая CakePHP, CodeIgniter, Zend Framework и т. Д.) Или, если вы не являетесь разработчиком, вы можете развернуть готовое приложение из списка, который включает в себя WordPress, Drupal, Joomla, Media Wiki и другие.
Вы также получаете бесплатный SSL, если используете домен .phpfogapp.com
.
Настройка вашей учетной записи
Даже регистрация в PHPFog очень быстрая, вам просто нужно указать адрес электронной почты, выбрать пароль, и вы в нем. Кредитная карта изначально не требуется, потому что каждая учетная запись начинается с бесплатного плана, который использует общее облако с 3 приложения, 100 МБ дискового пространства и 20 МБ хранилища MySQL. Если вы решите перейти на премиум-план, у вас будет частное облако с выделенными ресурсами (ЦП, ОЗУ, дисковое хранилище и база данных). Премиум-планы также позволяют масштабировать количество используемых серверов баз данных и приложений даже на один или два дня, оплачивая только то, что вы используете, с минимальной единицей в 24 часа.
Самая «сложная» вещь, которую вам придется сделать во время настройки учетной записи, — это настройка ключей SSH, но сотрудники PHPFog предоставляют вам это пошаговое руководство . И это все, ты в! Страница вашего аккаунта должна выглядеть так:
Создайте свое приложение
Со страницы вашей учетной записи вы должны увидеть окно общего облака. Создайте новое приложение, используя кнопку «Новое приложение». Ваш экран должен выглядеть примерно так:
Оттуда вы можете развернуть любое из готовых приложений (выше) или приложение на основе фреймворка (ниже), где первым выбором будет пустое приложение PHP. Нам нужно выбрать Slim, потому что версия этого фреймворка, предоставляемая PHPFog, включает в себя некоторые модификации, чтобы улучшить производительность, мы получим материал Bootstrap позже. На следующем шаге нам предлагается выбрать данные нашего приложения: имя домена приложения и пароль MySQL.
Ваше приложение будет доступно по адресу http://myappname.phpfogapp.com
, я выбрал http://subscribers.phpfogapp.com
для своего приложения.
В течение следующих 2 или 3 минут платформа PHPFog будет работать для вас, создавая среду для вашего приложения и предоставляя вам полный доступ к консоли приложения:
На этом этапе вы можете клонировать репозиторий приложения на свой локальный компьютер, используя ваш любимый инструмент Git:
[исходный код] $ git clone [email protected]: subscrib.phpfogapp.com ./SlimSubscribeers
Клонирование в ‘./SlimSubscribeers’…
Добавлена идентификация: /Users/ragman/.ssh/id_rsa (/Users/ragman/.ssh/id_rsa)
Пульт: Подсчет объектов: 82, сделано.
удаленный: сжатие объектов: 100% (74/74), сделано.
удаленный: всего 82 (дельта 35), повторно 0 (дельта 0)
Получение объектов: 100% (82/82), 75,79 КиБ, сделано.
Разрешение дельт: 100% (35/35), сделано.
[/исходный код]
Я просто клонировал каталог приложения внутри DocumentRoot моего локального Apache, чтобы мой URL для разработки был http://localhost/SlimSubscribers/
.
Создайте приложение локально
Теперь у вас есть локальная копия приложения «Привет, мир» Slim Framework. В первую очередь нам нужно добавить другие компоненты и организовать наш проект.
Как вы можете видеть на скриншоте выше, корень приложения содержит только два файла: .htaccess
который остается «как есть», и файл index.php
который будет нашим основным контроллером приложения.
Я создал каталог lib
куда я переместил полный пакет Slim, а затем добавил еще две библиотеки. Библиотека db
— это простой PHP-класс, который охватывает PDO. Каталог cake
содержит два класса, извлеченных из платформы CakePHP, которые используются здесь для очистки и проверки пользовательского ввода. Оба класса доступны с пакетом кода этой статьи.
На этом этапе вы можете скачать официальный пакет Twitter Bootstrap вместе с последней версией jQuery и заполнить другие каталоги файлами css, js и image.
Затем создайте пустую базу данных на локальном сервере MySQL, назовите ее slim_subscribers
и используйте следующий запрос для создания таблицы subscribers
:
[исходный код] CREATE TABLE подписчиков (
id INT (11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
имя VARCHAR (128) НЕ NULL,
фамилия VARCHAR (128) НЕ ПУСТО,
электронная почта VARCHAR (128) НЕ NULL УНИКАЛЬНО,
созданный TIMESTAMP
);
[/исходный код]
Со всеми основными компонентами мы сосредоточим нашу работу на главном контроллере index.php
и каталоге templates
где будут храниться файлы веб-интерфейса. Приложение будет иметь две статические описательные страницы, home.php
и about.php
и страницу subscribe.php
которая содержит форму подписки. Все эти страницы будут содержать общий верхний и нижний колонтитулы, которые я собрал, начиная с примеров файлов, представленных Bootstrap на его веб-сайте.
Это заголовок:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title><?php echo (!empty($pageTitle))? $pageTitle . ' | ' : ''; ?>Slim Subscribe</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="Sample application with Slim Framework and Twitter Bootstrap"> <meta name="author" content="Your Name"> <!-- Le styles --> <link href="css/bootstrap.min.css" rel="stylesheet"> <style> body { padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */ } .form-actions { background-color: transparent; border: none; } </style> <link href="css/bootstrap-responsive.min.css" rel="stylesheet"> <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <!-- Le fav and touch icons --> <link rel="shortcut icon" href="http://www.sitepoint.com/wp-content/uploads/2012/04/ico/favicon.ico"> <link rel="apple-touch-icon-precomposed" sizes="114x114" href="http://www.sitepoint.com/wp-content/uploads/2012/04/ico/apple-touch-icon-114-precomposed.png"> <link rel="apple-touch-icon-precomposed" sizes="72x72" href="http://www.sitepoint.com/wp-content/uploads/2012/04/ico/apple-touch-icon-72-precomposed.png"> <link rel="apple-touch-icon-precomposed" href="http://www.sitepoint.com/wp-content/uploads/2012/04/ico/apple-touch-icon-57-precomposed.png"> </head> <body> <div class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> <a class="brand" href="<?php echo $baseurl ?>/">Slim Subscribe</a> <div class="nav-collapse"> <ul class="nav"> <li<?php if ('home' == $action) echo ' class="active"'; ?>><a href="<?php echo $baseurl ?>/">Home</a></li> <li<?php if ('subscribe' == $action) echo ' class="active"'; ?>><a href="<?php echo $baseurl ?>/subscribe">Subscribe</a></li> <li<?php if ('about' == $action) echo ' class="active"'; ?>><a href="<?php echo $baseurl ?>/about">About</a></li> </ul> </div><!--/.nav-collapse --> </div> </div> </div> <div class="container">
Первое, что я добавил, — это динамический заголовок, переменная $pageTitle
будет передаваться файлом контроллера, поэтому мы можем иметь разные заголовки для каждой страницы или откат к заголовку по умолчанию. В этой версии Bootstrap по умолчанию предоставляется метатег viewport
для поддержки мобильных устройств и планшетов. Затем идут стили, сначала основной bootstrap.css
, затем некоторые встроенные настройки и, наконец, bootstrap-responsive.css
который использует запросы @media
для адаптации макета для небольших экранов.
Другим компонентом Bootstrap по умолчанию является JavaScript-код shim, загруженный из Google, который поддерживает HTML-теги для IE 8 и более ранних версий. В конце раздела заголовка я разместил ссылки на значки избранного и сенсорного экрана, оставив значки загрузки по умолчанию, найденные на Github.
Общее тело начинается с отзывчивого компонента Navbar. Я скопировал базовый код из документации Bootstrap и добавил переменные $action
, введенные контроллером Slim, чтобы инициировать активные состояния ссылки. Стандартный плагин javascript «collapse» внутри bootstrap.js
позаботится о том, чтобы преобразовать навигацию в выпадающий список для маленьких экранов.
Код нижнего колонтитула:
<footer> <p>(cc) 2012 Your Name &bull; Some rights reserved.</p> </footer> </div> <!-- /container --> <!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline --> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/jquery-1.7.1.min.js"></script>')</script> <script src="js/bootstrap.min.js"></script> </body> </html>
Файл нижнего колонтитула просто закрывает контейнер приложения и вставляет библиотеку jQuery и файл bootstrap.js
.
Мы можем начать работать с индексным файлом сейчас. Этот файл обрабатывает все URL-адреса, передаваемые .htaccess
которые не сопоставляются с реальными файлами на сервере.
/** * Simple Configuration */ if ('localhost' == $_SERVER['SERVER_NAME']) { $config['app']['home'] = '/SlimSubscribers'; $config['db'] = array( 'host' => 'localhost', 'user' => 'myuser', 'pass' => 'mypass', 'name' => 'slim_subscribers', ); } else { $config['app']['home'] = ''; $config['db'] = array( 'host' => 'mysql-shared-xx.phpfog.com', 'user' => 'Slim-xxxxx', 'pass' => 'THE ONE YOU CHOSE', 'name' => 'yourdb_phpfogapp_com', ); } // end if /** * Step 1: Require the Slim PHP 5 Framework */ require 'lib/Slim/Slim.php'; // ...add other accessory libraries require_once 'lib/db/db.class.php'; require_once 'lib/cake/sanitize.php'; require_once 'lib/cake/validation.php'; /** * Step 2: Instantiate the Slim application */ $app = new Slim();
В первых строках я делаю быструю настройку, размещая детали базы данных и базовый путь, который будет добавлен ко всем ссылкам. Мне нужно это потому, что моя локальная версия работает в подпуть localhost. Затем загружается платформа Slim и другие библиотеки, и создается новый объект приложения Slim с настройками по умолчанию (дополнительную информацию см. В документации Slim).
Как только объект $app
создан, мы можем его использовать. Slim позволяет нам сопоставить URL-адреса, которые мы хотим обработать, с нашими пользовательскими функциями, и все необработанные URL-адреса по умолчанию рассматриваются как ошибки 404. Простейшим отображением являются две статические страницы:
// Map the Home route $app->get('/', function () use($app, $config) { $pageTitle = 'Welcome to Slim Subscribe'; $action = 'home'; $app->render('home.php', array( 'pageTitle' => $pageTitle, 'action' => $action, 'baseurl' => $config['app']['home'], )); }); // Map the About route $app->get('/about', function () use($app, $config) { $pageTitle = 'About Slim Subscribe'; $action = 'about'; $app->render('about.php', array( 'pageTitle' => $pageTitle, 'action' => $action, 'baseurl' => $config['app']['home'], )); });
Метод $app->get()
принимает заданный путь URI ( /
и /about
) в качестве первого параметра и отображает HTTP-метод GET
для этого URL на функцию, переданную в качестве второго параметра. В этом примере я использую две анонимные функции (требуется PHP 5.3 или выше), которым я $config
переменные $app
и $config
которые будут рассматриваться как локальные в области видимости.
Сначала я устанавливаю текущие значения $pageTitle
и $action
, затем с помощью метода $app->render()
я говорю объекту приложения загрузить home.php
шаблона home.php
(первый параметр) из каталога templates
по умолчанию и ввести переменные давать, используя массив, предоставленный в качестве второго параметра. То же самое сделано для /about
URI. home.php
шаблона home.php
выглядит так:
<?php require_once 'header.php';?> <div class="hero-unit"> <h1>Hello, world!</h1> <p>This is a simple subscription form application built with Slim Framework, styled with Bootstrap and hosted on PHPFog.</p> <p> <a class="btn btn-primary btn-large" href="<?php echo $baseurl ?>/subscribe">Subscribe now</a> or <a class="btn" rel="external" href="http://phpfog.com/">Learn more about PHPFog &raquo;</a> </p> </div> <?php require_once 'footer.php'; ?>
И about.php
шаблона about.php
:
<?php require_once 'header.php';?> <div class="page-header"> <h1>About Slim Subscribe</h1> </div> <div class="row content"> <div class="span12"> <p>Slim Subscribe is a demo application written to test the PHPFog cloud platform.</p> <ul> <li>Built using <a href="http://www.slimframework.com/">Slim Framework</a></li> <li>Styled with <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a></li> </ul> </div> </div> <hr/> <?php require_once 'footer.php'; ?>
Оба файла содержат общий заголовок и нижний колонтитул. В домашнем шаблоне используется компонент под названием hero-unit
, предназначенный для демонстрации контента, и несколько хорошо стилизованных кнопок. Страница about использует стандартный компонент page-header
и контейнер с одним столбцом для своего содержимого.
URL /subscribe
является основной функциональностью приложения, имеет структуру, аналогичную двум другим страницам, но также должна обрабатывать интерфейс формы и данные, публикуемые пользователем. Код контроллера для подписки:
// Map the Subscribe route $app->map('/subscribe', function () use($app, $config) { $pageTitle = 'Join Slim Subscribe'; $action = 'subscribe'; $data = array(); $errors = array(); if ($app->request()->isPost()) { // Sanitize $data = $app->request()->post(); $data = Sanitize::clean($data, array('escape' => FALSE)); // Validate $valid = Validation::getInstance(); if (!$valid->email($data['email'])) { $errors['email'] = 'Invalid email address'; } // end if if (!$valid->notEmpty($data['firstname'])) { $errors['firstname'] = 'Please insert your name'; } // end if if (!$valid->notEmpty($data['lastname'])) { $errors['lastname'] = 'Please insert your last name'; } // end if // Check/Insert subscriber if (empty($errors)) { if ($db = Db::getConnection()) { try { // First check $query = "SELECT COUNT(id) AS count FROM subscribers WHERE email = :email"; $stmt = $db->prepare($query); $stmt->bindParam(':email', $data['email'], PDO::PARAM_STR); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); if ((int) $row['count'] > 0) { throw new PDOException("This email address is already subscribed!"); } // end if // Then Insert $query = "INSERT INTO subscribers (firstname, lastname, email) VALUES(:firstname, :lastname, :email)"; $stmt = $db->prepare($query); $stmt->bindParam(':firstname', $data['firstname']); $stmt->bindParam(':lastname', $data['lastname']); $stmt->bindParam(':email', $data['email']); $stmt->execute(); $app->flashNow('success', "Subscription completed successfully!"); } catch (PDOException $e) { $app->flashNow('error', "Unable to process your request: " . $e->getMessage()); } // end try } else { $app->flashNow('error', "Unable to access access database"); } // end if } // end if } // end if $app->render('subscribe.php', array( 'pageTitle' => $pageTitle, 'action' => $action, 'data' => $data, 'errors' => $errors, 'baseurl' => $config['app']['home'], )); })->via('GET', 'POST');
Прежде всего вы можете заметить, что метод, используемый для сопоставления URI, отличается. Я использую метод $app->map()
который позволяет указать более одного метода HTTP. В этом случае метод GET отображает форму, а метод POST обрабатывает представленные данные. Первая и последняя часть функции похожи на другие страницы: в начале мы устанавливаем некоторые переменные, а в конце они передаются в файл представления. Эта функция использует две дополнительные переменные: $errors
которая содержит ошибки проверки ввода, и $data
которая хранит данные, предоставленные пользователем.
Метод $app->request()->isPost()
проверяет опубликованные данные. Если что-то опубликовано, оно затем копируется в массив $data
с помощью $app->request()->post()
. Размещенные данные сначала очищаются для удаления недопустимых символов, а затем проверяются, и любая найденная ошибка сохраняется в массиве $errors
. Если нет ошибок проверки данных, сценарий пытается подключиться к базе данных, метод $app->flashNow()
используется для сохранения сообщения об ошибке в текущем сеансе. Шаблон будет иметь доступ к ассоциативному массиву $flash
содержащему все сообщения.
Логика базы данных происходит внутри оператора try/catch
. Сначала мы проверяем, зарегистрирован ли адрес электронной почты, уже зарегистрирован, и в этом случае выдается исключение. Затем мы пытаемся вставить опубликованные данные в таблицу подписчиков, $app->flashNow()
используется как в случае успеха, так и в случае ошибки. Это привело нас непосредственно к интерфейсу подписки.
<?php require_once 'header.php';?> <div class="page-header"> <h1>Join Subscribe</h1> </div> <?php if (!empty($flash['error'])): ?> <div class="alert alert-error"> <a class="close" data-dismiss="alert">×</a> <?php echo $flash['error'] ?> </div> <?php endif; ?> <?php if (!empty($flash['success'])): ?> <div class="alert alert-success"> <?php echo $flash['success'] ?> <a href="<?php echo $baseurl ?>/subscribe">Do it again &raquo;</a> </div> <?php else: ?> <div class="row content"> <div class="span12"> <form class="form-horizontal" action="" method="post"> <div class="control-group<?php if (!empty($errors['email'])) echo ' error' ?>"> <label for="email" class="control-label">Your email address</label> <div class="controls"> <input name="email" id="email" class="input-xlarge" type="email" placeholder="[email protected]" value="<?php echo (!empty($data['email'])) ? $data['email'] : ''; ?>"> <?php $field = 'email'; if (!empty($errors[$field])):?><span class="help-inline"><?php echo $errors[$field] ?></span><?php endif; ?> </div> </div> <div class="control-group<?php if (!empty($errors['firstname'])) echo ' error' ?>"> <label for="firstname" class="control-label">Name</label> <div class="controls"> <input name="firstname" id="firstname" class="input-xlarge" type="text" placeholder="John" value="<?php echo (!empty($data['firstname'])) ? $data['firstname'] : ''; ?>"> <?php $field = 'firstname'; if (!empty($errors[$field])):?><span class="help-inline"><?php echo $errors[$field] ?></span><?php endif; ?> </div> </div> <div class="control-group<?php if (!empty($errors['lastname'])) echo ' error' ?>"> <label for="lastname" class="control-label">Last Name</label> <div class="controls"> <input name="lastname" id="lastname" class="input-xlarge" type="text" placeholder="Smith" value="<?php echo (!empty($data['lastname'])) ? $data['lastname'] : ''; ?>"> <?php $field = 'lastname'; if (!empty($errors[$field])):?><span class="help-inline"><?php echo $errors[$field] ?></span><?php endif; ?> </div> </div> <div class="form-actions"> <button class="btn btn-primary btn-large" type="submit">Subscribe</button> </div> </form> </div> </div> <?php endif; ?> <hr/> <?php require_once 'footer.php'; ?>
Шаблоны общего и нижнего колонтитула включены, а для page-header
используется компонент page-header
. Сразу после заголовка страницы скрипт проверяет переменную сеанса $flash
наличие глобальных ошибок приложения. Сообщение об ошибке отображается с использованием классов оповещений, предоставляемых Bootstrap. Якорь «х» автоматически перехватывается Javascript и используется для закрытия окна сообщения.
Аналогичная проверка выполняется для сообщений об успехе, отображаемых с использованием класса «alert-success». Если у нас нет сообщений об успехе, либо были какие-то ошибки, либо данные не были опубликованы, поэтому форма отображается. Форма подписки создается с использованием компонента, предоставляемого Bootstrap. Я выбрал «форму-горизонтальный» тип формы, и каждый элемент управления оборачивается элементом div «control-group». Для каждой контрольной группы я проверяю, не вызвали ли связанные данные какую-либо ошибку проверки, и если это так, то в группу добавляется класс «error», и рядом с полем ввода отображается соответствующее сообщение.
Последняя строка файла контроллера index.php
— это $app->run();
и он отвечает за выполнение приложения Slim.
Протестируйте и разверните
На этом этапе наше приложение должно работать идеально с нашего локального компьютера. Все, что нам нужно сделать, чтобы опубликовать это:
- создайте таблицу подписчиков в нашей удаленной базе данных, используя phpMyAdmin, предоставленный PHPFog,
- выполните команду
git push
из нашего любимого интерфейса git.
Ваше приложение запущено и работает по адресу http://theappname.phpfogapp.com
и оно идеально подходит для настольных компьютеров, планшетов и смартфонов.
Резюме
Несомненно, PHPFog — это еще один отличный инструмент для быстрой публикации ваших приложений. Есть еще некоторые ограничения, большинство из которых связано с тем, что это еще молодая платформа. Тем не менее, читая документацию, вы видите, что сотрудники за кулисами действительно усердно работают, чтобы заполнить пробелы, и в то же время они дают вам советы и рекомендации для обхода текущих ограничений.
Кроме того, есть интерфейсная структура Bootstrap, которая в сочетании с Slim или любой другой вашей любимой библиотекой PHP является отличной отправной точкой для создания потрясающих пользовательских интерфейсов и позволяет вам сосредоточиться на программировании. На самом деле, у меня ушло больше времени на написание этой статьи, чем на создание примера приложения с нуля. 🙂
Я надеюсь, что этот урок повысит вашу смелость, чтобы изучить другие возможности платформы. Удачного кодирования!