In this tutorial you will learn how to set-up NGINX with HHVM and MongoDB. However, this tutorial is not meant to be an all inclusive guide on how ito run NGINX and HHVM in a production environment.
After the initial set-up, we continue explaining how to get started with the MongoDB driver and library for HHVM to write our first project.
In this tutorial, we will be using a Debian system, with NGINX installed
through apt-get
and HHVM installed from source into
/usr/local/hhvm/3.9.1
(with the binary being at
/usr/local/hhvm/3.9.1/bin/hhvm
).
We simply install NGINX by running apt-get install nginx-full
. If this
fails to start, it is likely that you already have Apache running on the same
port. If that happens, you will see the following lines in
/var/log/nginx/error.log
:
2015/09/29 10:19:27 [emerg] 22445#22445: bind() to 0.0.0.0:80 failed (98:Address already in use) 2015/09/29 10:19:27 [emerg] 22445#22445: bind() to [::]:80 failed (98: Address already in use)
If this happens, simple remove Apache by running apt-get remove apache2
.
I have installed HHVM from a source build, mostly because I needed one with some of my own patches and debug symbols. The folks at Facebook also provide pre-built packages, which is probably what you want to use in production and development. You can find them at the HHVM Wiki.
You need to install the hhvm
and hhvm-dev
packages. The latter is
needed so that we can compile the MongoDB HHVM extension later on.
Because I installed from source, I had to do some extra work. I had to create
/var/run/hhvm
:
sudo mkdir -p /var/run/hhvm
sudo chown www-data.www-data /var/run/hhvm
sudo mkdir /etc/hhvm
sudo touch /etc/hhvm/php.ini
sudo chown derick /etc/hhvm/php.ini
(So that you don't have tosudo
to edit the file)echo "date.timezone=Europe/London" >> /etc/hhvm/php.ini
(To see whether it actually works)
I also had to start HHVM as www-data
user. For now, I am running it in the
foreground in server mode as follows:
sudo -u www-data -s /usr/local/hhvm/3.9.1/bin/hhvm \ --mode server \ -vServer.Type=fastcgi \ -vServer.FileSocket=/var/run/hhvm/sock
Once HHVM runs, we need to tell NGINX how to talk to HHVM for .php
files. Although this is perhaps not the most clean way of doing this, you
can add the following snippet to /etc/nginx/sites-enabled/default
, just
after the location / {
… }
section:
location ~ \.php$ { fastcgi_pass unix:/var/run/hhvm/sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
After adding the snippet, you should restart NGINX:
sudo service nginx restart
Just to see that it all works now, we will create a project directory and in
there, we place a index.php
file with a phpinfo()
file:
Create the project directory:
sudo mkdir -p /var/www/html/my-first-project
Change permissions to your user:
sudo chown derick.www-data /var/www/html/my-first-project
Create the file
/var/www/html/my-first-project/index.php
. From now on, I will not include the full path/var/www/html/my-first-project/
when I mention file names. Put the following content in this file:<?php phpinfo(); ?>
Now in your browser, request the page
http://gargleblaster/my-first-project/index.php
(but adjust the
hostname). This should then show a page starting with "HHVM Version 3.9.1"
followed by several tables with information.
The MongoDB driver is the part that links up the PHP in HHVM with the database server. To install and register the driver with HHVM, you need to take the following steps:
- Download the latest driver from https://github.com/mongodb/mongo-hhvm-driver/releases. At the moment, there is only hhvm-mongodb-1.0beta1.tgz so we will be using this one in the examples.
- Unpack the archive:
tar -xvzf hhvm-mongodb-1.0beta1.tgz
cd
into the newly created directory:cd hhvm-mongodb-1.0beta1
- Generate the configure files for the bundled libraries. For this to work,
you need to have the
automake
,autoconf
andlibtool
packages installed (throughapt-get
).cd libbson; ./autogen.sh; cd ..
cd libmongoc; ./autogen.sh; cd ..
- Generate the Makefile:
hphpize && cmake .
- Build the driver:
make
- Install the driver:
sudo make install
. This last step tells you were it has installed the binary filemongodb.so
. In my case, it showed:Installing: /usr/local/hhvm/3.9.1/lib/hhvm/extensions/20150212/mongodb.so
Now that the driver is installed, you need to enable it in HHVM. In order to do
this, you need to add the following lines to /etc/hhvm/php.ini
, swapping
out my directory name for the that showed when running make install
:
hhvm.dynamic_extension_path=/usr/local/hhvm/3.9.1/lib/hhvm/extensions/20150212 hhvm.dynamic_extensions[mongodb]=mongodb.so
After you have done that, you need to stop HHVM by pressing Ctrl-C in the shell running HHVM, and then start it again as above:
sudo -u www-data -s /usr/local/hhvm/3.9.1/bin/hhvm \ --mode server \ -vServer.Type=fastcgi \ -vServer.FileSocket=/var/run/hhvm/sock
In order to test that it works, we edit our index.php
file, and replace
its contents with:
<?php var_dump(phpversion("mongodb")); ?>
This should output something like:
string(9) "1.0beta1"
The driver implements the same API as its PHP variant, and documentation can therefore be found in the PHP Documentation.
The last thing we still need to install to get started on the application itself, is the PHP library.
The library needs to be installed with Composer. In your project directory
(/var/www/html/my-first-project
) type:
curl -sS https://getcomposer.org/installer -o installer.php
hhvm installer.php
rm installer.php
This downloads and installs Composer. Wherever it says "Use it: php
composer.phar", it of course means hhvm composer.phar
.
With Composer installed, we can now install the library:
hhvm composer.phar require mongodb/mongodb
It outputs something akin to:
Using version ^0.2.0 for mongodb/mongodb ./composer.json has been created Loading composer repositories with package information Updating dependencies (including require-dev) - Installing mongodb/mongodb (0.2.0) Downloading: 100% Writing lock file Generating autoload files
And it has created several files (composer.json
, composer.lock
) as
well as the vendor
directory that contains the library.
Composer manages your dependencies, and will provide you with a loader that you include with the following at the start of your script:
<?php require 'vendor/autoload.php';
With this done, you can now use any of the functionality as described in the documentation.
If you are familiar with the old driver, it should look too much out of place. The only big difference is that the Database class is only used for Database specific operations. The CRUD operations on the Collection class are also renamed for clarity, and to be in accordance with a new language-agnostic specification.
As an example, this is how you insert a document into the beers collection of the demo database:
<?php require 'vendor/autoload.php'; // include Composer goodies $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); $collection = new MongoDB\Collection($manager, "demo.beers"); $result = $collection->insertOne( [ 'name' => 'Hinterland', 'brewery' => 'BrewDog' ] ); echo "Inserted with Object ID '{$result->getInsertedId()}'"; ?>
Instead of the original document being modified to add the newly generated
_id
field, this is now part of the result that comes back from the
insertOne
method.
After insertion, you can of course also query the data that you have just
inserted. For that, you use the find
method which returns a cursor that
you can iterate over:
<?php require 'vendor/autoload.php'; // include Composer goodies $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); $collection = new MongoDB\Collection($manager, "demo.beers"); $result = $collection->find( [ 'name' => 'Hinterland', 'brewery' => 'BrewDog' ] ); foreach ($result as $entry) { echo $entry->_id, ': ', $entry->name, "\n"; } ?>
You might have noticed that instead of accessing the _id
and name
fields is no longer done through an array access operator. Instead, they are
now properties of a stdClass
object. You can find more information on how
serialisation and deserialisation between PHP variables and the BSON stored in
MongoDB in the persistence specification.