Cron job – running PHP in the background

Background jobs

If you wish to write responsive web applications, you will need to  push some operations in the background. That way you can just register request for some long running task and immediately return to the client.

If you search the web, there are many ways how to achieve this, but not so many implementation are ready to do it in constraint environment of simple web hosting.

My web page is hosted by GoDaddy with so called “Linux hosting with cPanel”. I have PHP and MySql, but not much beside this. GoDaddy luckily allows cron jobs.  We simply register some command as “cron job” to run unattended at specified frequency.

For proof of concept I will need simple php program and run it as cron job.  At each cron job iteration we will insert one record into database table. We just want to proof that php program can run in the background as  cron job.

Create some database and add “tasklog” table.

Our simple PHP program is :

To test it, just put the “taskrun.php” in your “public_html” folder and navigate to it. If something will go wrong in the program, the settings for exceptions are set to report it to the client. Please test the program until everything not running smoothly.

Register cron job

You can put program file to any folder. If folder is not under “public_html” folder, it will be inaccessible from the public web and that way will be much more secure. We create new “jobs” folder under our root home folder and move “taskrun.php” program there.

In the “cPanel” locate “Advanced” section and select “Cron Jobs”:

2015-10-22 22_42_41-cPanel - MainCreate new job with a one minute frequency as:

To prevent email to be sent for each iteration, we put redirection into the command ( > /dev/null 2>&1 ).

2015-10-22 22_45_26-cPanel - Cron JobsWait a minute and check if there are some records in the “tasklog” table. You will see something like this:

2015-10-23 00_10_00-n1plcpnl0026.prod.ams1.secureserver.net _ localhost _ bisagasamples _ tasklog _

Success !

Of course, this is only proof of concept for running something unattended in the background. But I think there are already some open source job-task runner out there.

 

Include Bootstrap in Symfony 2 application

Bootstrap

The best tool to design nice, responsive, mobile first web applications is bootstrap framework. It is  also integrated as form design theme in symfony.

Before you can use it in your symfony application, you will need to install it.

The easiest way is with a web front-end package manager – bower. You should install node first and then install bower with npm package manager.  Then including resources in your twig templates is as easy as use asset component.

Isn’t this little to much to start with ?

Shortcut

If you don’t know what node/npm/bower is or if you don’t want to know (for now) 🙂 , you can just use bootstrap directly from publicly accessible  CDN links. Do not forget to include jquery library first, it is required by bootstrap.

Just don’t forget, if you take shortcuts, you get cut short.

Using bower

Why we needs front-end package management ?  With front-end package manager we simplify installing and updating project dependencies for client side libraries. Bower also check inter-dependencies between those libraries and won’t install the package incompatible with one that’s already installed.

If you use bower for front-end package management  and don’t want to use default download directory (“bower_components”), just create local config file “.bowerrc”:

Then you can install bootstrap with a command :

You will get two sub folders, “bootstrap” and “jquery”, inside “libs” folder.

Asset component

With asset component we generate URL addresses of web assets such as CSS, stylesheets, graphics and Javascript files. This means that you can change location of assets at one place  in configuration file.

We create new  “assets” section in “framework”  section of config.yml file and add three “packages” inside :

With that in place we can define URL location in our template file with asset function, for example:

Second parameter in asset function is package location from config.yml file.

And the final twig file with all required includes for bootstrap is :

 

 

Doctrine DBAL – working with database

In this article I am going to cover using MySql database in Symfony 2 application.

I will use the simplest possible database access technology PHP offers – PDO,  but in slightly extended form of Doctrine DBAL. So if you want to use Doctrine ORM , this article is not right place to start.

Before we begin

We need some sample data in the database,  so we create a database “dbsamples” with “country” table and import data from this csv file. Because I will not use full Doctrine ORM ,  generating db schema is not an option, I will create database manually.

You can use phpMyAdmin for that,  it is usually installed by default. If you need true utf8 database, you need to set character set to utf8mb4.

Connecting to the database

Because we use Symfony standard framework, we already have  connection parameters in a configuration file (“parameters.yml”).

I added one new parameter here, an array of custom driver options (“database_options”). By default all received data to php are stringified, it means you get all data in strings. To receive native data types from the database (int as integer for example), you need to set those options and use prepared statements. But this options will only work if you have luck and your hosting installed and enabled  “mysqlnd” native driver, check your hosting for the driver type.

In the config.yml file, this parameters are mapped to dbal connection  parameters:

When we are in the symfony controller file (as in \AppBundle\Controller\DefaultController.php for example), we get connection directly from the container:

or more specific for DBAL connection :

but because aquired connections are not pooled (php connections do not support connection pool yet), is actually the same if you create new connection by yourself :

Selecting data

Selecting data in DBAL is easy and intuitive, just use connections executeQuery method. If you use parameters in SQL statement, this will create prepared statement for you and bind parameters automatically. You should always use prepared statements because they are more secure and more efficient as plain text statements.

But there is even better way, using QueryBuilder object and assembling SQL statement with PHP code.

Fetch data to types

To get result from a statement, we need to execute one of the “fetch” methods.

By default we receive each result row as an array, or as array of arrays for multiple records. We can even fetch directly to an instance of an class:

Don’t forget we have all the power of PDO library at our disposal.

With little help from variable type hinting , we get full code completion on received object instance in the IDE:

2015-09-27 11_05_12-Untitled - paint.net 4.0.6Well, that’s of course possible only in case we use same exact names in database and in php class :

Custom columns mapping

Well, you really need to have a very good reason to select different names for columns in database, but sometimes you are not original owner of database. In that case you could introduce mapping function like this:

Prepare sample for mapping

We create new table “currency” in the database  :

and write new class “Currency” in php :

We do not want push to far in this direction, we could start developing a new ORM or something and that is not our intention. We want to retain full power of SQL language in the application, without need to write to much PHP or SQL code manually.

Usage example:

Mapping array contain database columns first (as keys) and class properties second (as values).

Inserting data

Inserting data is straightforward :

Because insert command expect array as second parameter, we simply convert object instance ($country)  to associative array.  After record is inserted, we inspect last inserted value in auto numbered column and return value to the program.

Update data

Update is very similar to insert, except we need to add third parameter to find existing record :

Delete data

And deleting is event simpler:

I didn’t mentioned that all commands are available as query builder methods.

Working with transactions

There is full transaction support directly in php code. We must explicitly start transaction and commit after last database command. In case of errors we need to call rollback on the used connection.

If you think this is little verbose and want to shorten the code, you actually can, just use closure with “transactional” function :

 

Installing the php_intl extension

Enabling php_intl extension

If you need internationalization extension (php_intl.dll), and you have similar development environment as I have, then follow this steps:

Open Ampps manager under PHP , enable internationalization extension (php_intl.dll) and click Apply.

2015-09-16 22_41_09-Program ManagerThat was simple , yes ?

To check if extension is available, you need to start “php -i” in command line and search for “intl” :

Well, I got this error:

The procedure entry point __crtCreateSymbolicLinkW could not be located in the dynamic link library MSVCR110.dll

The procedure entry point __crtCreateSymbolicLinkW could not be located in the dynamic link library MSVCR110.dll

We need latest Visual C++ Runtime, but even if we have one on the windows installed, something prevent PHP to load correct DLL.

After a while and lot of experimenting I figure out that MSVCR110.dll is installed in PHP folder as part of Ampps installation (H:\Ampps\php folder for me). Windows will load this local DLL from folder where program started and will not search for one on the system.

I just rename dll file to something else (“not_used_MSVCR110.dll”) and check again. This time “php -i” was executed without errors and I found “intl” settings in generated output .

There is one more location where MSVCR110.dll is installed (H:\Ampps\apache\bin). This is obviously inside apache runtime system and I renamed that too.

I am not sure if this is the best way to solve this problem, but for now I am satisfied.

 

Symfony – demo application

Install demo application

Symfony provide demo application as a learning resource.  To install it just enter “demo” as parameter to “symfony” command.

Start demo application

To start newly installed app, navigate to:

First page of application :

2015-09-16 21_53_17-Symfony Demo applicationIf demo application doesn’t work as expected and you get error like this :

An exception has been thrown during the rendering of a template (“The Symfony\Component\Intl\DateFormatter\IntlDateFormatter::__construct() method’s argument $locale value NULL behavior is not implemented.  Only the locale “en” is supported. Please install the “intl” extension for full localization capabilities.”) in blog/post_show.html.twig at line 35.

Just repair one line of php code in “IntlDateFormatter.php” file, as described in details in this fix .

File is placed inside demo app source tree , in my case this is:

Open file and change first “if” statement in “__constructor” method to reflect second line :

Save file and navigate to application again, this time should work as expected.