В прошлых уроках я показал вам, как создать систему управления содержимым плоской файловой системы (CMS) с использованием Go , Node.js и Ruby .
В этом уроке я собираюсь взять ту же модель проектирования и построить сервер с использованием PHP . Поскольку PHP сам по себе не является сервером, а обычно связан с веб-сервером Apache , я покажу вам, как настроить веб-сервер Apache в виртуальной системе Vagrant .
Настройка и загрузка библиотек
Для начала вам нужно установить PHP в вашей системе. Перейдите на сайт PHP и загрузите версию для своей системы. В большинстве дистрибутивов Linux и во всех системах Mac OS X уже установлен PHP.
Затем установите Composer , менеджер пакетов для PHP, аналогичный npm для Node.js. Чтобы установить Composer, введите в терминале следующее:
1
|
php -r “readfile(‘https://getcomposer.org/installer’);” |
|
После установки Composer установка библиотек для сервера будет следующей. Сначала создайте каталог для проекта с файлами из раздела Построение CMS: структура и стилизация или распакуйте загрузку для этого руководства. После настройки перейдите в этот каталог и введите:
1
2
3
4
5
|
composer require slim/slim “^3.0”
composer require erusev/parsedown
composer require zordius/lightncandy:dev-master
composer require “talesoft/tale-jade:*”
composer install
|
Эти строки устанавливают четыре библиотеки, составляющие сервер: Slim Router — это библиотека маршрутизации для обработки входящих запросов к серверу, Parsedown переводит Markdown в HTML, Handlebars — это библиотека шаблонов, а Jade Library — это сокращенная форма HTML, которая Я использую, чтобы сделать страницы индекса для сообщений.
Создание index.php
В верхней части каталога проекта создайте файл index.php. Сервер Apache ожидает, что главная страница сайта будет иметь это имя. В этом файле поместите следующий код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
//
// Program: phpPress
//
// Description: This is a full flat file
// system CMS that mimics the
// organization of goPress.
// Since goPress server can not
// be run on a shared server,
// phpPress will work there and
// offer easy migration to
// goPress if the site is moved
// to a VPS.
//
require ‘vendor/autoload.php’;
//
// Load libraries used.
//
//
// HandleBars: https://github.com/zordius/lightncandy
//
use LightnCandy\LightnCandy;
//
// Jade Library: https://github.com/Talesoft/tale-jade
//
use Tale\Jade;
|
Оператор require позволяет PHP знать, как загружать различные библиотеки, установленные с помощью Composer. Затем вы говорите PHP использовать библиотеки LightnCandy и Jade.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
//
// Slim Router: http://www.slimframework.com/
//
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
$app = new \Slim\App;
//
// Set an Error Handler.
//
$c = $app->getContainer();
$c[‘errorHandler’] = function ($c) {
return function ($request, $response, $exception) use ($c) {
return $c[‘response’]->withStatus(400)
->withHeader(‘Content-Type’, ‘text/html’)
->write(ProcessPage($parts[‘layout’],“ErrorPage”));
};
};
//
// This line will cause Slim not to catch errors.
// production server.
//
unset($app->getContainer()[‘errorHandler’]);
|
Затем вы настраиваете маршрутизатор Slim, создавая экземпляр объекта приложения Slim и устанавливая обработчик ошибок. С установленным обработчиком ошибок вы никогда не получите отладочную информацию при возникновении ошибки. Поэтому во время разработки вам нужно сбросить обработчик ошибок. Но для производства закомментируйте последнюю строку с unset.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
//
// Get the server.json information in to global site variables.
//
$site = __DIR__ .
$style = “Basic”;
$layout = “SingleCol”;
$styleDir = ‘./themes/styling/’ .
$layoutDir = ‘./themes/layouts/’ .
$parts = Array();
$parts[“CurrentLayout”] = “SingleCol”;
$parts[“CurrentStyling”] = “Basic”;
$parts[“ServerAddress”] = “http://localhost:8080”;
$parts[“SiteTitle”] = “Test Site”;
$parts[“Sitebase”] = “./site/“;
$parts[“TemplatBase”] = “./themes/“;
$parts[“Cache”] = false;
$parts[“MainBase”] = ““;
//
// Load relevant items in the layouts directory.
//
$parts[“layout”] = file_get_contents($layoutDir . ‘/template.html’);
//
// Load relevant items in the styles directory.
//
$parts[“404”] = file_get_contents($styleDir . ‘/404.html’);
$parts[“footer”] = file_get_contents($styleDir . ‘/footer.html’);
$parts[“header”] = file_get_contents($styleDir . ‘/header.html’);
$parts[“sidebar”] = file_get_contents($styleDir . ‘/sidebar.html’);
$parts[“ErrorPage”] = “<h1 class=’Error’>There was a server error!</h1>“;
//
// Load everything in the parts directory.
//
$d = dir($site . ‘/parts/’);
while (false !== ($entry = $d->read())) {
if((strcmp($entry,“..“)!=0)&&(strcmp($entry,“.“)!=0)) {
$pathparts = pathinfo($entry);
$parts[basename($pathparts[‘filename’])] = figurePage($site . ‘/parts/’ . $pathparts[‘filename’]);
}
}
$d->close();
|
Следующий раздел кода — создание хеш-таблицы $parts
для хранения фрагментов информации, используемых в шаблонах. Затем программа добавляет все содержимое каталога частей сайта в хеш-таблицу. Таким образом, вы можете создавать многократно используемые фрагменты для добавления на любую страницу.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
//
// Function: SetBasicHeader
//
// Description: This function will set the basic header
// information needed.
//
// Inputs:
// $response The response object to be
// sent to the browser.
//
function SetBasicHeader($response) {
$newResponse = $response->withAddedHeader(“Cache-Control”, “max-age=2592000, cache”);
$newResponse = $newResponse->withAddedHeader(“Server”, “phpPress — a CMS written in PHP from Custom Computer Tools: http://customct.com.“);
return($newResponse);
}
|
Функция SetBasicHeader()
устанавливает заголовок возврата для всех страниц. Это устанавливает функции управления кэшем и имя сервера. Если вам нужна дополнительная информация заголовка, это то место, где вы ее установите.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//
// Array of shortcodes and their functions.
//
$shcodes = Array(
‘box’ => function($args, $inside) {
return(“<div class=’box’>” . $inside . “</div>“);
},
‘Column1’ => function($args, $inside) {
return(“<div class=’col1′>” . $inside . “</div>“);
},
‘Column2’ => function($args, $inside) {
return(“<div class=’col2′>” . $inside . “</div>“);
},
‘Column1of3’ => function($args, $inside) {
return(“<div class=’col1of3′>” . $inside . “</div>“);
},
‘Column2of3’ => function($args, $inside) {
return(“<div class=’col2of3′>” . $inside . “</div>“);
},
‘Column3of3’ => function($args, $inside) {
return(“<div class=’col3of3′>” . $inside . “</div>“);
},
‘php’ => function($args, $inside) {
return(“<div class=’showcode’><pre type=’syntaxhighlighter’ class=’brush: php’>” . $inside . “</pre></div>“);
},
‘js’ => function($args, $inside) {
return(“<div class=’showcode’><pre type=’syntaxhighlighter’ class=’brush: javascript’>” . $inside . “</pre></div>“);
},
‘html’ => function($args, $inside) {
return(“<div class=’showcode’><pre type=’syntaxhighlighter’ class=’brush: html’>” . $inside . “</pre></div>“);
},
‘css’ => function($args, $inside) {
return(“<div class=’showcode’><pre type=’syntaxhighlighter’ class=’brush: css’>” . $inside . “</pre></div>“);
}
);
|
Хеш-таблица $shcodes
содержит все функции шорткода для обработки элементов на веб-странице. Функции, которые я здесь написал, просты, но при необходимости они могут быть более сложными. Это дает возможность встраивать более динамичный код в ваши веб-страницы.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
//
// Function: processShortcodes
//
// Description: This function will expand all
// shortcodes in the page given to
// it.
//
function processShortcodes($page) {
global $shcodes;
$result = ““;
while(preg_match(“/\-\[(\w+)(.*)\]\-/i”, $page, $match) == 1) {
$num = count($match);
$command = $match[1];
$cmdarg = ““;
if($num > 2) {
$cmdarg = $match[2];
}
$spos = strpos($page,“-[{$command}“);
$result .= substr($page, 0, $spos);
$page = substr($page,$spos + 4 + strlen($command) + strlen( $cmdarg));
$sepos = strpos($page,“-[/{$command}]-“);
$inside = trim(substr($page, 0, $sepos));
if(strcmp($inside,““) != 0) {
$inside = processShortcodes($inside);
}
$page = substr($page, $sepos + 5 + strlen($command));
//
// If the command name exists in the
// shortcodes hash table, then run the
// function.
//
if( array_key_exists($command, $shcodes) ) {
$result .= call_user_func($shcodes[$command], $cmdarg, $inside);
}
}
$result .= $page;
return($result);
}
|
Функция processShortCodes()
найдет, выполнит и вставит результаты processShortCodes()
. Эта функция находит все шорткоды на странице, рекурсивно вызывая себя для вложенного содержимого и остальной части страницы.
Шорткод имеет следующий синтаксис:
1
2
3
|
-[name arg]-
contents
-[/name]-
|
Имя — это имя шорткода, arg
— аргументы, переданные шорткоду, а contents
— это часть страницы, которая заключена в шорткод. -[
и ]-
действуют так же, как <
и >
в HTML.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
//
// Create the HandleBar helpers array.
//
$helpers = Array(
‘flags’ => LightnCandy::FLAG_HANDLEBARS |
‘helpers’ => Array(
‘save’ => ‘save_helper’,
‘date’ => ‘date_helper’,
‘cdate’ => ‘cdate_helper’
)
);
//
// Function: save_helper
//
// Description: This helper will save the given text to
// the given name.
// latter in the document.
//
// Inputs:
// $args The arguments sent to the
// helper function.
//
function save_helper($args) {
global $parts;
$arg = implode(” “, $args);
$hparts = explode(“|“, $arg);
if(count($hparts) == 2) {
$parts[$hparts[0]] = $hparts[1];
return $hparts[1];
} else {
return $parts[$hparts[0]];
}
}
//
// Function: date_helper
//
// Description: This function formats the current date
// according to the formatting string given.
//
// Inputs:
// $args The arguments sent to the helper
//
function date_helper($args) {
$dateFormat = implode(” “, $args);
return date($dateFormat);
}
//
// Function: cdate_helper
//
// Description: This function formats the date given
// according to the formatting string given.
//
// Inputs:
// $args The arguments sent to the helper
//
function cdate_helper($args) {
return date($args[0], $args[1]);
}
|
В следующем разделе содержатся вспомогательные функции для добавления помощников в механизм шаблонов Handlebars. Вспомогательные функции: save
, date
и cdate
. Функция save
берет имя и текст. Везде, где имя указано в макросе, данный текст заменит его. Функция date берет текущую дату и форматирует ее в соответствии с заданной строкой форматирования. Функция cdate
берет дату и строку форматирования. Он установит указанную дату в заданный формат.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
//
// Function: ProcessPage
//
// Description: This function will process a page into
// the template, process all Mustache
// macros, and process all shortcodes.
//
// Inputs:
// $layout The layout for the page
// $page The pages main contents
//
function ProcessPage( $layout, $page ) {
global $site, $parts, $helpers;
//
// We need a temporary file for creating the
// Handlebars rendering function.
// need to change this depending on your system.
//
$php_inc = “/var/tmp/handlebarsTemp.php”;
//
// Get the page contents.
//
$parts[‘content’] = figurePage($page);
//
// First pass on Handlebars.
//
$phpStr = LightnCandy::compile($layout, $helpers);
file_put_contents($php_inc, $phpStr);
$renderer = include($php_inc);
$page = $renderer($parts);
//
// Process the shortcodes.
//
$pageShort = processShortcodes($page);
//
// Second pass Handlebars.
//
$phpStr = LightnCandy::compile($pageShort, $helpers);
file_put_contents($php_inc, $phpStr);
if($phpStr != ““) {
$renderer = include($php_inc);
$page = $renderer($parts);
}
//
// Return the results.
//
return($page);
}
|
Следующая функция — ProcessPage()
. Эта функция принимает макет страницы и содержимое страницы. Он объединит их с помощью движка шаблонов LightnCandy Handlebars. Затем на полученной странице ищутся шорткоды. Полученная страница после этого снова запускается через LightnCandy. Браузер получает вывод от LightnCandy.
01
02
03
04
05
06
07
08
09
10
|
//
// Setup the routes routines.
//
function page( $pageAddress ) {
global $site, $parts;
$page = ProcessPage( $parts[‘layout’], “{$site}/pages/{$pageAddress}“);
return($page);
}
|
Функция page()
определяет страницу для отправки пользователю. Функция получает адрес страницы от маршрутизатора и вызывает ProcessPage()
для создания страницы.
1
2
3
4
5
6
|
function posts($postType, $blog, $pageAddress ) {
global $site, $parts;
$page = ProcessPage( $parts[‘layout’],“{$site}/posts/{$postType}/{$blog}/{$pageAddress}“);
return($page);
}
|
Функция posts()
работает так же, как функция page()
для содержимого posts()
. Маршрутизатор передает значения типа записи, блога и адреса страницы из маршрута. Затем эта функция использует ProcessPage()
чтобы создать страницу для возврата.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
function figurePage( $page ) {
global $site, $parts;
$result = ““;
if(isset($parts[$page])) {
//
// A site partial was specified.
//
$result = $parts[$page];
}else if(file_exists(“{$page}.html”)) {
//
// It is a html piece.
//
$result = file_get_contents(“{$page}.html”);
} else if(file_exists(“{$page}.md”)) {
//
// It is a markdown piece.
// it on.
//
$Parsedown = new Parsedown();
$result = file_get_contents(“{$page}.md”);
$result = $Parsedown->text($result);
$result = str_replace(“"“,“\““,$result);
} else if(file_exists(“{$page}.amber”)) {
//
// It is a Jade (using the golang name for the
// extension) page.
//
$jade = new Jade\Renderer();
$jade->addPath(dirname($page));
$result = $jade->render(basename($page));
} else {
$result = $parts[“404”] ;
}
//
// give the resulting page content.
//
return($result);
}
|
Функция figurePage()
возвращает правильное содержимое страницы на основе заданного имени. Функция будет искать файл с расширением .html. Если он есть, он читает его и отправляет вызывающей подпрограмме.
Затем функция ищет расширение .md. Если он есть, он читает его, преобразует Markdown в HTML и возвращает его в вызывающую подпрограмму. Далее, функция видит, существует ли такая с расширением .amber. Если он есть, он читает его, преобразует синтаксис Jade в HTML и возвращает его вызывающей функции.
1
2
3
4
5
6
7
8
|
//
// This route handles the main or home page.
//
$app->get(‘/’, function(Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse = $newResponse->getBody()->write(page(‘main’));
return($newResponse);
});
|
Эта функция маршрута отображает главную или домашнюю страницу веб-сайта. Это сработает для всех запросов к доменному имени с или без ‘/’.
01
02
03
04
05
06
07
08
09
10
11
|
//
// This route handles the favicon loading.
//
$app->get(‘/favicon.ico’, function(Request $request, Response $response){
global $site;
$newResponse = SetBasicHeader($response);
$newResponse = $newResponse->withAddedHeader(“Content-type”, “image/ico”);
$newResponse->getBody()->write(file_get_contents(“{$site}/images/favicon.ico”));
return($newResponse);
});
|
Это определение маршрута соответствует конкретному запросу: /favicon.ico. Это дает значок для веб-сайта. Возвращает изображение «/images/favicon.ico» в каталоге сайта.
01
02
03
04
05
06
07
08
09
10
11
12
|
//
// This route handles all the stylesheets loading as one
// sheet.
//
$app->get(‘/stylesheets’, function(Request $request, Response $response) {
global $site;
$newResponse = $response->withHeader(“Content-type”, “text/css”);
$newResponse = SetBasicHeader($newResponse);
$newResponse->getBody()->write(file_get_contents(“{$site}/css/final/final.css”));
return($newResponse);
});
|
Этот маршрут получает скомпилированную таблицу стилей и возвращает ее запрашивающей стороне. Скомпилированная таблица стилей всегда называется «/css/final/final.css».
01
02
03
04
05
06
07
08
09
10
11
|
//
// This route handles the loading of the scripts.
//
$app->get(‘/scripts’, function(Request $request, Response $response) {
global $site;
$newResponse = $response->withAddedHeader(“Content-type”, “text/javascript”);
$newResponse = SetBasicHeader($newResponse);
$newResponse->getBody()->write(file_get_contents(“{$site}/js/final/final.js”));
return($newResponse);
});
|
Этот маршрут всегда возвращает скомпилированный файл JavaScript, найденный в «/js/final/final.js».
01
02
03
04
05
06
07
08
09
10
11
12
|
//
// This route handles all the image routes.
//
$app->get(‘/images/{image}’, function(Request $request, Response $response) {
global $site;
$ext = pathinfo($request->getAttribute(‘image’), PATHINFO_EXTENSION);
$newResponse = SetBasicHeader($response);
$newResponse = $newResponse->withAddedHeader(“Content-type”, “image/$ext”);
$newResponse->getBody()->write(file_get_contents(“{$site}/images/” . $request->getAttribute(‘image’)));
return($newResponse);
});
|
Этот маршрут обрабатывает все запросы на изображения. {image}
указывает коду маршрутизатора дать имя образу функции. Вызов функции $request->getAttribute()
возвращает значение.
01
02
03
04
05
06
07
08
09
10
11
|
//
// This route handles all the video items.
//
$app->get(‘/videos/{video}’, function(Request $request, Response $response) {
global $site;
$newResponse = SetBasicHeader($response);
$newResponse = $response->withAddedHeader(“Content-type”, “video/mp4”);
$newResponse->getBody()->write(file_get_contents(“{$site}/video/” . $request->getAttribute(‘video’)));
return($newResponse);
});
|
Этот маршрут получает все видео-запросы и отправляет их в браузер.
1
2
3
4
5
6
7
8
|
//
// This route handles all the blog posts pages.
//
$app->get(‘/posts/blogs/{blog}’, function( Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse->getBody()->write(posts(“blogs”,$request->getAttribute(‘blog’), “index”));
return($newResponse);
});
|
Этот маршрут возвращает список записей блога и их резюме. Переменная {blog}
будет именем блога, для которого будут перечислены записи.
1
2
3
4
5
|
$app->get(‘/posts/blogs/{blog}/{post}’, function( Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse->getBody()->write(posts(“blogs”,$request->getAttribute(‘blog’), $request->getAttribute(‘post’)));
return($newResponse);
});
|
Этот маршрут получает отдельную запись в блоге. {blog}
— это название блога, а {post}
— это запись в блоге, которую нужно получить.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
//
// This route handles all the news posts pages.
//
$app->get(‘/posts/news/{news}’, function( Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse->getBody()->write(posts(“news”,$request->getAttribute(‘news’), “index”));
return($newResponse);
});
$app->get(‘/posts/news/{news}/{post}’, function( Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse->getBody()->write(posts(“news”,$request->getAttribute(‘news’), $request->getAttribute(‘post’)));
return($newResponse);
});
|
Запросы маршрутизатора новостей работают так же, как запросы маршрутизатора блога.
01
02
03
04
05
06
07
08
09
10
|
//
// This route will process all the pages.
// catch all types of routes other than the home page, this
// route should handle the unknown pages as well.
//
$app->get(‘/{page}’, function( Request $request, Response $response) {
$newResponse = SetBasicHeader($response);
$newResponse->getBody()->write(page($request->getAttribute(‘page’)));
return($newResponse);
});
|
Это общий маршрут страницы. Все запросы, которые не соответствуют ни одному из предыдущих запросов, будут инициировать этот запрос.
1
2
3
4
5
6
|
//
// Respond to requests.
//
$app->run();
?>
|
Этот последний бит кода запускает сервер. Эта функция выполнит всю обработку запроса. По возвращении интерпретатор PHP завершит и закроет соединение с браузером пользователя.
Этот PHP-сервер работает совершенно иначе, чем другие серверы этой серии. Эта процедура запускается и заканчивается для каждого запроса, в то время как другие серверы продолжают обрабатывать запросы. Следовательно, этот PHP-сервер занимает больше времени для обработки запросов из-за загрузки и выгрузки подпрограмм.
Подготовка сервера
Теперь настроить сервер. Один из самых простых способов получить стек Apache и PHP — использовать Vagrant . Чтобы установить на Mac, используйте Homebrew с этой командой:
1
|
brew cask install vagrant
|
Если у вас есть система Windows или Linux, используйте установщики с веб-сайта Vagrant. На веб-сайте также есть автономный установщик для Mac, но, установив Homebrew, вы можете получать автоматические обновления, выполнив:
1
|
brew update
|
После установки создайте файл с именем Vagrant в каталоге проекта. В этом файле поместите следующий код:
1
2
3
4
5
6
|
Vagrant.configure(“2”) do |config|
config.vm.box = “ubuntu/trusty64”
config.vm.provision :shell, path: “bootstrap.sh”
config.vm.network :forwarded_port, host: 8080, guest: 8080
config.vm.synced_folder “/full/path/to/code/directory”, “/vagrant”
end
|
Это файл конфигурации Vagrant. Он сообщает Vagrant, на какую виртуальную машину создать компоновку, какой скрипт нужно запустить, чтобы настроить блок для вашего сервера, какие порты на виртуальной машине сопоставить с портами на вашем главном компьютере, а также папку для синхронизации с папкой / vagrant в виртуальная машина. Вам нужно установить полный путь к каталогу на вашем компьютере вместо /full/path/to/code/directory
.
Затем создайте файл bootstrap.sh
и добавьте в него этот скрипт:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
sudo apt-get update
sudo apt-get install -y apache2
#
# Setup modules in apache that will be needed.
#
sudo ln -s /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/headers.load
sudo ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load
#
# Setup apache on port 8080 and configure apache to read the .htaccess files for
# access changes.
#
sudo cat /etc/apache2/sites-available/000-default.conf |
sudo mv /var/tmp/sites.conf /etc/apache2/sites-available/000-default.conf
sudo cat /etc/apache2/ports.conf |
sudo mv /var/tmp/ports.conf /etc/apache2/ports.conf
sudo cat /etc/apache2/apache2.conf |
sudo mv /var/tmp/apache2.conf /etc/apache2/apache2.conf
#
# setup php5
#
sudo apt-get install -y php5
#
# Setup the server root directory
#
sudo rm -rf /var/www/html
sudo ln -fs /vagrant /var/www/html
#
# reload apache
#
sudo service apache2 reload
|
Этот скрипт загрузится на веб-сервер Apache и настроит его. После настройки Apache он устанавливает PHP версии 5, устанавливает корневой каталог для сервера и запускает службу Apache. Все это настроит виртуальную машину так, как необходимо для этого проекта, и будет иметь корневой каталог сервера, получающего файлы из каталога вашего проекта. Любые изменения, которые вы вносите в каталог проекта, мгновенно становятся доступными для сервера.
В каталоге проекта создайте файл с именем .htaccess и поместите этот код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
# 1 YEAR
<FilesMatch “\.(ico|pdf|flv)$“>
Header set Cache-Control “max-age=29030400, public”
</FilesMatch>
# 1 WEEK
<FilesMatch “\.(jpg|jpeg|png|gif|swf)$“>
Header set Cache-Control “max-age=604800, public”
</FilesMatch>
# 2 DAYS
<FilesMatch “\.(xml|txt|css|js)$“>
Header set Cache-Control “max-age=172800, proxy-revalidate”
</FilesMatch>
# 1 MIN
<FilesMatch “\.(html|htm|php)$“>
Header set Cache-Control “max-age=60, private, proxy-revalidate”
</FilesMatch>
|
Это сообщает серверу Apache, как обрабатывать запросы для этого сайта и для автоматического кэширования запросов. Файл index.php получает каждый запрос к серверу.
Запуск сервера
Чтобы запустить сервер, выполните следующую команду в каталоге проекта:
1
|
vagrant up
|
Это загрузит виртуальную машину, если она еще не установлена в вашей системе, запустит сценарий инициализации и запустит сервер. Для просмотра сайта откройте браузер по адресу http: // localhost: 8080 .
Браузер должен показать вышеуказанную страницу. Сервер теперь онлайн и готов к вашим дополнениям.
Если веб-сайт недоступен для просмотра, вам следует проверить разрешения для всех файлов на сайте. OS X часто имеет их только для чтения. Вам нужно сделать их читаемыми во всем мире с помощью следующей команды в каталоге проекта:
1
|
chmod -R a+r .
|
Это обеспечит возможность чтения файлов сервером Apache на виртуальной машине.
Чтобы остановить сервер, выполните следующую команду в каталоге проекта:
1
|
vagrant halt
|
Чтобы узнать больше об использовании Vagrant, пожалуйста, прочитайте документацию Vagrant . Вы также можете ознакомиться со многими учебниками по Vagrant здесь, на Envato Tuts +. Я использовал инструмент Hobo для создания моих Vagrant-файлов. Это отличный инструмент для настройки, запуска и управления системами Vagrant в OS X.
Вывод
Теперь, когда вы знаете, как создать простой, но мощный веб-сервер с использованием языка PHP, пришло время экспериментировать. Создавайте новые страницы, сообщения, встраиваемые части и шорткоды. Эта простая платформа намного быстрее, чем WordPress, и она полностью под вашим контролем.
В отличие от других веб-серверов этой серии, эта CMS на основе PHP может работать на любой учетной записи общего хостинга. Я использую его для веб-сайта моего министерства на DreamHost . Я не оптимизировал изображения, но это все еще довольно хорошо. Расскажите мне о вашем сервере в комментариях ниже.