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.

create table tasklog (
    id int not null auto_increment,
    created datetime,
    primary key (id)
)

Our simple PHP program is :

<?php
try {
    $host = "localhost";
    $dbname = "your_database";
    $user = "your_db_user";
    $pass = "your_password";

    # MySQL with PDO_MYSQL
    $db = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
    $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

    $stmt = $db->prepare("INSERT INTO tasklog(`created`) VALUES(NOW())");
    $stmt->execute();
  
    $db = null;
}
catch(PDOException $e) {
    echo $e->getMessage();
}

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:

/usr/local/bin/php "$HOME/jobs/taskrun.php" > /dev/null 2>&1

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.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">        
        <title>{% block title %}Bisaga application{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
          <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
          <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->        
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
        <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
        <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <!-- Include all compiled plugins (below), or include individual files as needed -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    </body>
</html>

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”:

{
  "directory": "libs"
}

Then you can install bootstrap with a command :

H:\Ampps\www\webapp05\www\> bower install --save bootstrap

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 :

framework:
    assets:
        packages:
            jquery:
                base_path: /libs/jquery/dist/
            bootstrapjs:
                base_path: /libs/bootstrap/dist/js/
            bootstrapcss:
                base_path: /libs/bootstrap/dist/css/

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

 <link rel="stylesheet" href="{{ asset('bootstrap.min.css', 'bootstrapcss') }}">

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

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

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">        
        <title>{% block title %}Bisaga application{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
        <link rel="stylesheet" href="{{ asset('bootstrap.min.css', 'bootstrapcss') }}">
        <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
        <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
        <!--[if lt IE 9]>
          <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
          <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->        
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
        <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
        <script src="{{ asset('jquery.min.js', 'jquery') }}"></script>
        <!-- Include all compiled plugins (below), or include individual files as needed -->
        <script src="{{ asset('bootstrap.min.js', 'bootstrapjs')}}"></script>
    </body>
</html>