Stefan KoopmanschapCustomizing Sculpin: Highlight image and Facebook (27.7.2017, 23:10 UTC)

Over the past months I've been slowly customizing my Sculpin installation for this blog to fit my own liking a bit more. I've added a bit more styling including a beautiful background image and a transparent white background for the content column. Today I wanted to add a bit more. Two things specifically:

  • I wanted to control a bit more about how my blogposts are displayed when they are shared on Facebook
  • I wanted to have an optional image at the top of blogposts to make them look a bit better

It turns out this was actually quite easy, so here's a short description of what I did to make it work.


A quick search gave me the exact Facebook documentation I needed for setting up basic markup to make my site look better when shared on facebook. It basically means adding a couple of tags to the header of my HTML. Now that is easy! So in my source/_views/post.html I've added some lines to the head_meta block, which is the block in the layout that contains meta-data. I found this quite fitting.

    <meta property="og:url" content="{{ site.url }}{{ page.url }}" />
    <meta property="og:type" content="article" />
    <meta property="og:title" content="{{ page.title }}" />
    {% if %}
    <meta property="og:description" content="{{ }}" />
    {% else %}
    <meta property="og:description" content="{{ page.blocks.content|striptags|slice(0, 255) }}..." />
    {% endif %}
    {% if %}
    <meta property="og:image" content="{{ site.url }}{{ }}" />
    {% endif %}

Most of this seems pretty basic: I set the URL of the current article, I set the title to the title of the current article, the type is article (according to the Facebook documentation if you leave this out the default is website, which seems like an incorrect description of a blogpost). The description and highlight image meant I had to extend the standard blogpost format for the markdown file a bit more, I'll get back to that in a minute. But as you can see, I only add an image if I've set a highlight image, and I add a basic description unless a custom summary has been set in the blogpost.

Extending the Sculpin frontmatter

While I could just use a basic summary based on the blogpost and leave out the image, I wanted to have the flexibility to customize this a bit more. Luckily Sculpin allows you to extend the markdown frontmatter with your own custom tags. Basically, any tag (or hierarchy of tags) you add to the frontmatter in your blogpost markdown file automatically ends up in your data structure in the template. So now I can simple add some stuff to my blogpost, and I can use it in my template:

    highlight_image: /_posts/images/powertools.jpg
        name: Dorli Photography
    summary: I've customized my Sculpin a bit more to fit what I want with the blog.

As you can see, if I use a deeper hierarchy, I can access that by concatenating with dots, for instance the I use in the template comes from the above information.

Highlight image

Since I have a highlight image for Facebook anyway, I could actually use it to make my site look a bit nicer as well. So let's add the (optional) highlight image to the top of the blogpost as well. Since my (default, I think?) Sculpin template is split up into two templates, this required change in two places:

  • source/_layouts/default.html
  • source/_views/post.html

The first change is in the default layout: I need to add a block on top of the row that contains the blogpost to allow me to add custom HTML in my post template. This is a pretty simple task:

{% block topbanner %}{% endblock %}

The block will not contain anything by default, only if it gets overwritten by subtemplates. In our case, the template for the blogpost.

{% block topbanner %}
{% if %}
<div class="row-fluid">
    <div class="span12">
        <img src="{{ site.url }}{{ }}" style="width:100%" />
{% endif %}
{% endblock %}

In the source/_views/post.html I overwrite the block and add some content, but only if I've actually set a highlight_image for the blogpost. This ensures I can also blog without a highlight image, but als

Truncated by Planet PHP, read more at the original (another 1364 bytes)

SitePoint PHPHow to Build a Class Booking System with Acuity Scheduling (27.7.2017, 04:00 UTC)


This article was sponsored by Acuity Scheduling. Thank you for supporting the partners who make SitePoint possible.

I recently wrote an article about building an online system to book lessons with a driving instructor. Teaching someone to drive is relatively unique, in that it's guaranteed to be a one-to-one class — or at least, if you did find yourself sharing an instructor's time, then you'd have every right to feel short-changed.

Most other types of class, though, tend to have multiple participants. Unless they're delivered online, they'll most likely have a limit on the number of students due to logistical considerations.

Cookery classes usually have a very well-defined limit on the number of students — you can only really teach as many people as you have cooking stations or cookers. That's going to be the theme of this article — managing those "slots" in a cookery class. The principles remain the same for all sorts of other forms of tuition.

As before, we're going to take advantage of Acuity Scheduling in order to manage bookings for our classes, and everything that entails.

All of the code for this tutorial is available on Github.

What We're Going to Build

Thanchanok delivers Thai cookery classes. There's a general introductory course, as well as two more specialised courses - one covering the many and varied Thai curry pastes, and one that focuses specifically on the region in which she was brought up — the swelteringly hot Northern region around Chiang Mai. She owns a specially fitted-out kitchen to deliver these classes. Each has eight cooking stations. She typically runs around four classes a week — two of those slots for the introductory class which, as you might expect, is by far her most popular.

Currently her website includes an email address and telephone number for making bookings, but there are a number of issues with that. First is that it's easy to forget to update the website to indicate that it's fully-booked, which on occasion has left potential attendees disappointed and with a poor impression of the company.

The second is that she has to rely on good old-fashioned pen-and-paper to manage her list of pupils, along with their contact details and whether they've paid for the lesson ahead of time. She'd very much like to add a feature to her website that allows people to view class availability as well as book online, and to then help her class schedule and attendee lists. That's what we're going to do in the course of this tutorial.

Let's break down the requirements as far as the public-facing website is concerned:

  • The website needs to show all of the upcoming classes.
  • If a class is fully booked, it needs to say so.
  • Classes not fully booked should show the number of available slots.
  • Visitors should be able to book a place on classes that have availability.

By integrating all of this with Acuity Scheduling, we effectively get the back-end requirements handled without having to develop it ourselves:

  • The number of people who've booked for each upcoming class.
  • A list of attendees, along with their contact details.
  • Constant updates about upcoming classes and bookings.
  • Thanchanok's calendar, all in one place.

Let's get started.

Setting Up Acuity Scheduling

The first thing you'll need to do, if you haven't already, is to sign up at Acuity Scheduling. The free trial will be perfectly adequate for following along.

The next thing we need to do is set up the three classes. In Acuity terminology these are appointment types.

If you've just signed up, click the Create your Appointment types button at the top of the screen, or click Appointment Types under Business Settings on the sidebar.

Next, click the New Type of Group Class button.

Creating an appointment type

You'll need to name the class. For the purposes of this tutorial we'll call them Introduction to Thai Cookery, Thai Curry Pastes and

Truncated by Planet PHP, read more at the original (another 11695 bytes)

SitePoint PHPHow to Add Real-Time Notifications to Laravel with Pusher (26.7.2017, 16:00 UTC)

The modern web user expects to be informed of everything that happens within the application. You don’t want to be that one website that doesn’t even have the notifications dropdown found not just in all social media websites, but everywhere else these days, too. Luckily, with Laravel and Pusher, implementing this functionality is a breeze. […]

Continue reading %How to Add Real-Time Notifications to Laravel with Pusher%

SitePoint PHPWhy Is a String Called a String? (25.7.2017, 17:21 UTC)

Why is a string called a string? Have you ever given this some thought? We never use such a word in contexts other than programming for a set of letters sticking together, and yet - in programming it's as pervasive as the word "variable". Why is that, and where does it come from?

To find out, we have to tackle some related terms first. History lesson time!

Abstract old calendar illustration

The word font is derived from the French fonte - something that has been melted; a casting. Given that letters for printing presses were literally made of metal and smelted at type foundries, that makes sense.

The metal letters of a font

The terms uppercase and lowercase refer to the literal part of the case in which the font was transported. So the printer (person) had a heavy case he lugged around or had set up at a printing press, and in this case were two "levels" - an upper case, and a lower case. The upper case contained only - you guessed it - UPPERCASE letters, while the lower case only contained lowercase ones.

Printing press case

You'll notice that there were more lowercase letters than uppercase ones. This was to be expected - a letter could only be used once on a single page and after all, a written body of text will have many more lowercase letters than uppercase ones, as there was no such thing as Youtube comments and CAPS LOCK yet.

So how does all this relate to strings?

Well, as printing became more mainstream and printing presses began offering their services to individuals, not just newspapers and publishers, it is said they decided to charge based on the length of the printed material - length in feet. Granted, a lot of this is speculative, but if they strung together the produced, printed material, they could easily estimate the costs and bill customers. So we can conclude with a reasonable degree of certainty that they used the word string in this context as a sequence of characters.

Still, how does this relate to the programming field? I mean, you could say a string of anything in regards to anything at all and it would make a degree of sense in the non-programming world. It's just a word that can be applied generally quite easily to things, even though it generally isn't.

What if we look across academia for first references?

A vector illustration of a person looking through binoculars

In 1944's Recursively enumerable sets of positive integers and their decision problems we have a mention that could vaguely resemble the modern definition:

For working purposes, we introduce the letter 6, and consider "strings" of 1's and b's such as 11b1bb1.

In this paper, the term refers to a sequence of identical symbols, so a string of 1's or a string of b's. Not exactly our definition but it's a start.

Continue reading %Why Is a String Called a String?%

thePHP.ccDon't call instance methods statically (25.7.2017, 07:00 UTC)
Sammy Kaye Powers06: Submitting a PR to php-src (24.7.2017, 13:29 UTC)

We found some untested lines of code and wrote a useful test that covered the lines so let's submit our new test to the main php-src repo.

Don't we need to create an RFC to send a pull request? Not for bug fixes and tests, so we're in the clear.

Getting setup on GitHub

If you've never contributed to open source via GitHub before, check out my post, How to contribute to an open source project on GitHub.

First you need to sign up for GitHub and get your SSH keys set up.

We made sure we got the, "You've successfully authenticated" message to verify that our SSH keys were set up properly.

$ ssh -T
Hi SammyK! You've successfully authenticated, but GitHub does not provide shell access.

Then we made sure to set our name & email in the global git config. You should use the same email address that you use on GitHub.

$ git config --global "Sammy Kaye Powers"
$ git config --global ""

Forking the php-src repo

You'll need to create a fork of the main php-src repo to your account.

We listed our remotes to see the origin URL was set from the URL we used to clone the repo.

$ git remote -v
origin (fetch)
origin (push)

We need to change the origin URL to point to our fork we just created and then add a new remote called upstream that points to the php source repo.

Note: Make sure to replace {your-username} with your GitHub username.

$ git remote set-url origin{your-username}/php-src.git
$ git remote add upstream

Pushing the changes to our fork

Before we committed our change, we switched to the master branch since we want to create a new branch for our change off of master. We named the new branch test-json-depth-error but you can name it whatever you like.

$ git checkout master
$ git checkout -b test-json-depth-error

Then we staged, committed and pushed our new branch up to our fork on GitHub.

$ git add ext/json/tests/json_decode_error001.phpt
$ git commit -m "Add test for json_decode() depth error case"
$ git push origin test-json-depth-error

Send a pull request (PR)

We opened our fork up in GitHub and saw a message asking if we'd like to submit the new branch we created as a pull request back to the main php-src repo. So we clicked the button and created a pull request.

In order to keep our fork and local copy of the repo up to date, we made use of git fetch and git rebase.

$ git fetch upstream
$ git checkout master
$ git rebase upstream/master master
$ git push origin master

Congrats! You're now an official PHP internals contributor!



Truncated by Planet PHP, read more at the original (another 1140 bytes)

Zeev SuraskiYour PHP Stories (24.7.2017, 10:23 UTC)
Do you have an interesting story that involves PHP?  Something awkward, unexpected or inspiring that happened to you or that you witnessed that was related to PHP and/or its community?  Did PHP help you meet your spouse, otherwise change your life or enable you to change other people's lives?

If you answered any of these questions with a yes, and you'd like to share it with the world - please drop me a note at or @zeevs (Twitter).



Sarfraz AhmedSockets with PHP and Node (21.7.2017, 21:19 UTC)

I was looking to implement real time notifications system via sockets without having to use any third party services such as Pusher, etc. I just wanted to be able to send notifications from PHP side to the client and instantly show them on the web application similar to Facebook notifications.

First I came across ratchet library, it worked great but problem emerged when setting it up on secure connection (https) on my host (siteground), tried apache proxy module and everything else told on the internet but to no avail (it seems siteground has problem with ratchet on https) so in the end I had to drop ratchet.

Then I thought of using with Node+PHP and with my research I came across library (though it isn't updated recently) and this one worked wonderfully well both on non-secure and secure protocols allowing us to send and receive messages from PHP with node-based server.

Here are the steps that I followed to get my notification system working.


For your PHP application, install via composer:

composer require wisembly/

Install Node Dependencies

Create a directory in your project root and under it create a file named package.json with these contents:

    "name": "elephantIO_example_emitter",
    "version": "3.0.0",
    "main": "server.js",

    "scripts": {
        "start": "supervisor --debug server.js"

    "dependencies": {
        "": "~1",
        "winston": "*"

On newly created directory run command npm install --save. This will install and logger library.

In same newly created directory, create a file server.js with these contents:

var server     = require('http').createServer(),
    io         = require('')(server),
    logger     = require('winston'),
    port       = 1337;

// Logger config
logger.add(logger.transports.Console, { colorize: true, timestamp: true });'SocketIO > listening on port ' + port);

io.on('connection', function (socket){
    var nb = 0;'SocketIO > Connected socket ' +;

    socket.on('broadcast', function (message) {
        ++nb;'ElephantIO broadcast > ' + JSON.stringify(message));

        // send to all connected clients
        io.sockets.emit("broadcast", message);

    socket.on('disconnect', function () {'SocketIO : Received ' + nb + ' messages');'SocketIO > Disconnected socket ' +;


Run server.js file through node by typing node server.js, you should see message that server has started on specified port.

Client Side

Put following javascript code in your application's page/footer:

<script src='//'></script>

var socket = io.connect('//');

socket.on('connect', function () {

    socket.on('broadcast', function (data) {
        //socket.emit("broadcast", data);

    socket.on('disconnect', function () {

Sending Notification from PHP

Here is how you can send a message to all connected clients:

require __DIR__ . '/vendor/autoload.php';

use ElephantIO\Client;
use ElephantIO\Engine\SocketIO\Version1X;

$client = new Client(new Version1X('//'));

// send message to connected clients
$client->emit('broadcast', ['type' => 'notification', 'text' => 'Hello There!']);

and that's all there is to it.

Installing and Running Node on Production Site

I was on CentOSv6 and I installed node by following this guide. Then I created simple php file that will be run by cron so that node server is automatically started/restarted if it is not running:

$nodePath = 'your node binary path here';
$filePath = 'your server.js file path';
shell_exec($nodePath . ' ' . $filePath);

and then specify that file in cron to run at your specified time intervals.

Important Notes

  • I was having bit

Truncated by Planet PHP, read more at the original (another 868 bytes)

Sammy Kaye Powers05: Finding untested code (21.7.2017, 19:15 UTC)

Now that we know how to create tests and debug them when they fail, let's make a useful test that actually covers some untested code.

Finding untested lines of code

The PHP gcov website shows what lines of C code are covered by the test suite.

We took a long tangent to talk about the PHP_FUNCTION macro as well as the two ways Zend parse parameters (ZPP) works: with the zend_parse_parameters() function and the multi-line macro.

Eventually we found some uncovered lines of code in ext/json/json.c for the json_decode() function that checked that value for the depth param was greater than 0.

Creating a new test

We made sure that we had the ext/json extension installed.

$ sapi/cli/php -m | grep json

We tried to create a new test.

$ vi ext/json/tests/json_decode_error.phpt

But quickly realized that there was already a test there so we created a new file variation.

$ vi ext/json/tests/json_decode_error001.phpt

Then we created our test.

json_decode() - depth error
Sammy Kaye Powers me at sammyk dot me
# TestFest Chicago PHP UG 2017-07-18
<?php if (!extension_loaded('json')) die('skip ext/json required'); ?>
var_dump(json_decode('[]', false, 0));
Warning: json_decode(): Depth must be greater than zero in %s on line %d

We ran our test to see it pass with flying colors.

$ make test TESTS=ext/json/tests/json_decode_error001.phpt

At this point we could totally send our new test as a PR to the main php-src repo, but we wanted to see that this test actually covered the untested lines.

Generating a code coverage report

Since the PHP gcov website isn't updated regularly, we took Elizabeth Smith's advice and generated the code coverage reports locally.

First we have to install lcov.

$ sudo apt-get update
$ sudo apt-get install lcov

Then we can use the handy config.nice script to run configure again with all the previous flags in addition to any new ones. So we ran it with --enable-gcov since we already ran it with --enable-debug previously.

$ ./config.nice --enable-gcov

Next we had to delete all the previously compiled files with make clean so that everything could be recompiled with the appropriate flags that gcov needs.

$ make clean && make

Finally we wer

Truncated by Planet PHP, read more at the original (another 1981 bytes)

Federico CargneluttiWordPress Skimlinks (21.7.2017, 09:14 UTC)

To reproduce this issue:

1) Open this page in “Incognito” mode
2) Refresh the page multiple times and observe how js converts “foo” to “foo}

import {assert} from 'chai';
import sinon from 'sinon';
import mockRequire from 'mock-require';

describe('My module', () => {

    let module; // module under test
    let configMock;

    beforeEach(() => {
        configMock = {
            init: sinon.stub().returns("foo")

        // mock es6 import (tip: use the same import path)
        mockRequire("../../config.js", configMock);

        // require es6 module
        module = require("../../../app/services/content.js");

    afterEach(() => {
        // remove all registered mocks

    describe('Initialisation', () => {

        it('should have an load function', () => {



Filed under: Programming
LinksRSS 0.92   RDF 1.
Atom Feed   100% Popoon
PHP5 powered   PEAR
ButtonsPlanet PHP   Planet PHP
Planet PHP