Warning: Cannot modify header information - headers already sent by (output started at /home/robertpr/public_html/robblog/wp-includes/class-wp-user.php:1) in /home/robertpr/public_html/robblog/wp-includes/feed-rss2.php on line 8
Robert Price http://www.robertprice.co.uk/robblog Fri, 22 Jan 2016 13:36:23 +0000 en-GB hourly 1 Sparkline Creation Using PHP http://www.robertprice.co.uk/robblog/sparkline-creation-using-php/ Thu, 19 Jun 2014 17:45:41 +0000 http://www.robertprice.co.uk/robblog/?p=1543 Continue reading "Sparkline Creation Using PHP"]]> Sparkline graphs have had a bit of press lately, so I’ve been playing about with generating them on my commutes to and from work.

If you’ve not heard of them before, a Sparkline is a small graph that is often used inline with text.

I’ve been using PHP, so I’ve created a simple class called Spark, with a single static method called line. This returns a simple string as an inline graph from an array of values that have been passed in.

Sparkline Examples

Here’s an example plotting a simple staircase type graph.

require_once('lib/Spark.php');

echo Spark::line(array(1, 2, 3, 4, 5, 6, 7, 8)) . "n";

> ▁▂▃▄▅▆▇█

Here’s an example plotting a cosine wave.

$cos = array();
for($i=0; $i <= 360; $i=$i+20) {
    $cos[] = cos($i * M_PI / 180);
}
echo Spark::line($cos) . "n";

> ██▇▆▅▄▃▂▁▁▁▂▃▄▅▆▇██

Summary

The code is available on GitHub as php-spark, and is free to use. It was inspired by a simple project for Go called Spark, which was inspired from elsewhere.

]]>
Fixing The National Rail Mobile Website For iPhones http://www.robertprice.co.uk/robblog/fixing-national-rail-mobile-website-iphones/ Sun, 20 Apr 2014 20:42:28 +0000 http://www.robertprice.co.uk/robblog/?p=1530 Continue reading "Fixing The National Rail Mobile Website For iPhones"]]> I’ve been frustrated that the National Rail Enquiries mobile website doesn’t work properly on my Apple iPhone 4s, running iOS7, so I decided to take a look and see what is actually going on.

You can turn on debugging on your iPhone in the settings, so I turned this on, and loaded Safari on my Macbook Pro to take a look at what was actually happening.

The “Go” button on the mobile website acts as a submit button so I put a breakpoint on it to see what happened.

The event handler calls a function called setRecents, and it fails when it tries to save my recent stations to localStorage.

if (hasStorage) {
    localStorage.setItem("recentStations", recVal);
} else {
    setCookie("recentStations", recVal, 365);
}

The hasStorage global variable has a true value, allowing it to try to save to local storage, so I tried setting this to false and tried again. This time to website worked as it falls back to using cookies. So the problem is with localStorage on mobile Safari, I’m not sure why.

I then took a look to see how hasStorage was set. It was being set in the following function.

function checkStorage() {
    // Feature detect + local reference
    var storage,
    fail,
    uid;
    try {
        uid = new Date;
        (storage = window.localStorage).setItem(uid, uid);
        fail = storage.getItem(uid) != uid;
        storage.removeItem(uid);
        fail && (storage = false);
    } catch (e) {}
    if (storage) {
        hasStorage = true; //if localstorage available
    }
};

I set breakpoints through the function, reloaded and single stepped what was happening in the debugger.

The uid was correctly set to a Date object with the current date and time. The next line was where the problem occured. storage was assigned as a Storage object, but the setItem method failed. This meant that the storage variable was set, but an exception was thrown. The exception handler does nothing, so the line after was executed. This sees that storage is available, but not that it didn’t work, so sets hasStorage incorrectly to true.

The fix would be to modify the exception handler to set storage to false instead of doing nothing.

If any developers of the National Rail website are reading this, please add this line so I can use your website to plan my train journeys again using my iPhone!

The National Rail mobile website on an iPhone

All information correct at time of writing and publishing. 20th April 2014.

]]>
Returning A 410 HTTP Status Code In Apache http://www.robertprice.co.uk/robblog/returning-410-http-status-code-apache/ Fri, 28 Mar 2014 11:47:31 +0000 http://www.robertprice.co.uk/robblog/?p=1527 Continue reading "Returning A 410 HTTP Status Code In Apache"]]> I had an SEO requirement to return a 410 HTTP status code for any URL’s with /advanced-search/ in them.

The following snippet can be added to your Apache config to achieve this.

# Return a 410 for any URL's with advanced-search in
RewriteCond %{REQUEST_URI} /advanced-search/
RewriteRule ^.*$ - [G]

Here we’re looking in the URI for the words /advanced-search/ and if found, the RewriteRule below is activated.

The RewriteRule takes the URL, keeps it intact and sets the [G] flag. The [G] flag forces the server to return a 410 Gone status as it’s response.

If Apache sees a [G] flag, it returns immediately and no further rewrite rules are evaluated.

A 410 HTTP status code indicates that a resource was once available, but isn’t any more.

]]>
Vagrant Failing To Launch http://www.robertprice.co.uk/robblog/vagrant-failing-launch/ Mon, 18 Nov 2013 10:44:39 +0000 http://www.robertprice.co.uk/robblog/?p=1523 Continue reading "Vagrant Failing To Launch"]]> I use Vagrant based virtual machines to develop on. These are great as you can create custom environments at will without affecting your main machine.

Today I had the following error while trying to bring up my development environment.

wks:Vagrant robertprice$ vagrant up devvm
[ccfs] VM already created. Booting if it's not already running...
[ccfs] Clearing any previously set forwarded ports...
[ccfs] Forwarding ports...
[ccfs] -- 22 => 2222 (adapter 1)
[ccfs] -- 80 => 4567 (adapter 1)
[ccfs] Creating shared folders metadata...
[ccfs] Clearing any previously set network interfaces...
There was an error executing the following command with VBoxManage:

["hostonlyif", "create"]

For more information on the failure, enable detailed logging with
VAGRANT_LOG.

This turned out to be an error with VirtualBox, the virtualisation environment Vagrant uses. The solution is to force a restart of VirtualBox.

sudo /Library/StartupItems/VirtualBox/VirtualBox restart

I hope this helps others experiencing the same problem.

]]>
Data URI’s – Using and Generating http://www.robertprice.co.uk/robblog/data-uris-using-generating/ Wed, 30 Oct 2013 20:28:48 +0000 http://www.robertprice.co.uk/robblog/?p=1520 Continue reading "Data URI’s – Using and Generating"]]> A recent project of mine needed an image embedding into some HTML via JavaScript. Rather than use a separate image, I decided to embed it directly using a data URI.

An image in a data URI is the MIME type of the image and it’s content encoded with base64 into a string. This is great as it cuts down HTTP requests but does cause the initial page weight to increase and be difficult to update as each change means the image needs re-encoding. Modern browsers support data URI’s very well, but older browsers such as IE 7 and below won’t like it.

Examples Using A Data URI Encoded Image

HTML Example

Here’s how I can embed the image of a red cross into an HTML <img> tag.

<img src="data:image/gif;base64,R0lGODlhFAAUAJEAAP/9/fYQEPytrflWViH5BAAAAAAALAAAAAAUABQAQAJKhI+pGe09lnhBnEETfodatVHNh1BR+ZzH9LAOCYrVYpiAfWWJOxrC/5MASbyZT4d6AUIBlUYGoR1FsAXUuTN5YhxAEYbrpKRkQwEAOw==" alt="red cross" width="20" height="20" />

CSS Example

Here’s how I can embed the image of a red cross into background of an HTML element using CSS.

body { 
  background: url(data:image/gif;base64,R0lGODlhFAAUAJEAAP/9/fYQEPytrflWViH5BAAAAAAALAAAAAAUABQAQAJKhI+pGe09lnhBnEETfodatVHNh1BR+ZzH9LAOCYrVYpiAfWWJOxrC/5MASbyZT4d6AUIBlUYGoR1FsAXUuTN5YhxAEYbrpKRkQwEAOw==) no-repeat left center;
}

JavaScript Example

Here’s how I can add an image element with the red cross in to an HTML page using JavaScript.

var imagestring = "data:image/gif;base64,R0lGODlhFAAUAJEAAP/9/fYQEPytrflWViH5BAAAAAAALAAAAAAUABQAQAJKhI+pGe09lnhBnEETfodatVHNh1BR+ZzH9LAOCYrVYpiAfWWJOxrC/5MASbyZT4d6AUIBlUYGoR1FsAXUuTN5YhxAEYbrpKRkQwEAOw==";
var image = new Image();
image.src = imagestring;
image.onload = function() {
  document.body.appendChild(image);  
}

Encoding An Image To A Data URI

It’s easy to create the encoded image string using PHP as it comes with a Base64 encoder as part of the language. Automatically detecting the MIME type of an image is a bit harder, but we can use finfo_file with comes as an extension to PHP 5.3 and above to do this.

So assuming the filename of the image is in the variable $filename we can use the following code to get the mimetype, read the image and encode it to a data URI string.

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);

$contents = file_get_contents($filename);
echo "data:" . $mimetype . ";base64," . base64_encode($contents);

Conclusion

We’ve seen it’s easy to embed encoded images into code. I have wrapped the encoding routine into a command line PHP script and placed it on GitHub as php-base64-encode so it’s easy to quickly generate data URI’s.

]]>
DOMElement Content Extraction In PHP http://www.robertprice.co.uk/robblog/getting-contents-domelement-php/ Sun, 13 Oct 2013 21:08:36 +0000 http://www.robertprice.co.uk/robblog/?p=1509 Continue reading "DOMElement Content Extraction In PHP"]]> I was using PHP to parse an HTML document using the PHP DOM extension and got stuck on extracting the contents of an element.

The documentation doesn’t make it clear how to do this, until you look and see that a DOMElement inherits from DOMNode. In DOMNode, there is a nodeValue property that holds the content.

DOMElement Content Example

So if I had a HTML document already loaded into a variable $html, and I wanted to extract the value of an element with the ID of “example”, I could do something like this.

$doc = new DOMDocument()
$doc->loadHTML($html);
$element = $doc->getElementById('example');
echo $element->nodeValue;

An Alternative

A DOMNode also has a textContent property that can be used. This will return all the text for the node and descendants, which may not always be what you are hoping for.

]]>
Using Disqus On WordPress Behind A Proxy http://www.robertprice.co.uk/robblog/using-disqus-on-wordpress-behind-a-proxy/ Fri, 19 Jul 2013 10:37:29 +0000 http://www.robertprice.co.uk/robblog/?p=1502 Continue reading "Using Disqus On WordPress Behind A Proxy"]]> I had to implement the Disqus Comment System WordPress plugin on a website that will be located behind an outgoing proxy server. By default the Disqus WordPress plugin does not support proxies, so it is unable to run if a proxy is blocking it’s access to the internet.

Since WordPress 2.8, WordPress supports proxy servers using a few defined values, WP_PROXY_HOST and WP_PROXY_PORT. I have now forked the Disqus WordPress plugin on GitHub, and added support that will look to see if these exist, and use them if they do.

To use it, add the following to your wp-config.php file…

define('WP_PROXY_HOST', 'proxy.yourdomain.com');
define('WP_PROXY_PORT', '3128');

Changing the values to match those of your proxy server of course.

Now replace the url.php file in wp-content/plugins/disqus-comment-system/lib/api/disqus/url.php with the url.php found in my github repository.

Visit your WordPress admin panel and you should now be able to activate and configure the Disqus plugin successfully.

I have issued a pull request for my changes to be pulled back into the main plugin, but it’s up to Disqus is they want to implement this or not.

]]>
Allowing Apache To Write To The Vagrant Directory http://www.robertprice.co.uk/robblog/allowing-apache-to-write-to-vagrant/ http://www.robertprice.co.uk/robblog/allowing-apache-to-write-to-vagrant/#comments Wed, 26 Jun 2013 08:33:09 +0000 http://www.robertprice.co.uk/robblog/?p=1492 Continue reading "Allowing Apache To Write To The Vagrant Directory"]]> I had a problem with a website I was developing in Vagrant where the site neeeded to write out to the /vagrant directory (well actually a symlink that pointed there).

Apache doesn’t have permission to write there by default, but the following change to my Vagrantfile sorted it out.

config.vm.share_folder("v-root", "/vagrant", ".", :owner => "www-data", :group => "www-data")

This makes sure that the /vagrant directory is owned by a user that apache has permission to read and write with.

I hope this helps out others who have had the same problem.

Vagrant Update – October 2013

Newer versions of Vagrant have renamed v-root to vagrant-root, so the line for the VagrantFile is now

config.vm.share_folder("vagrant-root", "/vagrant", ".", :owner => "www-data", :group => "www-data")

]]>
http://www.robertprice.co.uk/robblog/allowing-apache-to-write-to-vagrant/feed/ 3
InnoTab 2 Video Conversion http://www.robertprice.co.uk/robblog/innotab-2-video-conversion/ http://www.robertprice.co.uk/robblog/innotab-2-video-conversion/#comments Sun, 17 Feb 2013 20:42:42 +0000 http://www.robertprice.co.uk/robblog/?p=1421 Continue reading "InnoTab 2 Video Conversion"]]> VTech Innotab 2 video conversion isn’t hard, but getting those settings right the first time can be, so I thought I’d share how I managed it.

The InnoTab 2 needs videos to have the following settings:

File Type AVI
Video Encoder MJPEG
Display Size 480×272
Frame Rate 15 fps
Bit Rate 2400 kbps
Audio Encoder PCM
Audio Channel Mono
Sampling Rate 22.05 kHz
Maximum File Size 2 GB

I have a Mac, so I used Handbrake which is an open source multiplatform video transcoder. It means it’s a free piece of software, that will run on Mac’s, PC’s and Linux boxes, and can be used to transform video from one format to another, such as one that will run on the InnoTab 2.

Once you have Handbrake installed, you need to use the following settings.

The Output Settings Format needs to be MP4 File.

In the video tab you need:

Video Codec: MPEG-4 (FFmpeg
Framerate (FPS): 15
Peak Framerate (VFR): selected
Video Quality: Constant Quality Selected, QP 20

In the audio tab you need:
Codec: AAC (CoreAudio)
Mixdown: Mono
Samplerate: 22.05
Bitrate: 48

In Picture Settings you need:
Width: 480
Height: 272

At this point you may want to save this as new preset, to save entering these details again for each video you want to convert. Click on Preset in the menu bar, and New Present. Call your Preset Name “InnoTab 2”, set the picture size to custom, and enter 480 272 for the width and height. The description is optional so enter something useful here if you want to, then Add.

To use a preset, you need to make sure the Preset Drawer is visible. It should be on the right hand side of the screen, and if not, click on Window in the menu bar, and select Preset Draw. Click on InnoTab 2 to get your InnoTab 2 settings.

Now, to convert a video, click on the Source icon on the top left of the screen. This will let you pick a video. Once selected, choose a name for the Destination File. Make sure you change the extension at the end from .mp4 to .avi, else your InnoTab 2 won’t be able to use the video. Now “Add To Queue”, and “Start”. It may take a while to convert but Handbrake will let you know when it’s ready.

To copy the video to your InnoTab 2, connect it to the your computer. Browse to one of the drives, and click on “LLN” then “MOVIES”. Drag and drop the movie you just converted into this folder. Unmount the InnoTab 2 from your computer and try looking for a movie on it. Your new movie should be at the top of the list and ready to watch.

Downloading A YouTube Movie

YouTube is a great source of videos to watch on your InnoTab 2, but you do need to be able to save them.

There are a few online sites that can help.

I have found an easy one to be ClipConverter.cc. You enter a URL of a page with the video you want to download, this can be a YouTube page. Select “Download” and save this so you can load it into Handbrake for conversion to your InnoTab 2.

A word of warning, ClipConverter.cc does launch popup windows, so be aware of this. Also be aware of Copyright and make sure you have the right to download and save a video to your InnoTab 2.

Conclusion

I hope this has helped other Innotab 2 users out there to get video content onto their device.

I have saved these settings to GitHub, so they are ready to import directly into Handbrake, Innotab 2 Handbrake Settings.

]]>
http://www.robertprice.co.uk/robblog/innotab-2-video-conversion/feed/ 14
POSTing JSON To A Web Service With PHP http://www.robertprice.co.uk/robblog/posting-json-to-a-web-service-with-php/ http://www.robertprice.co.uk/robblog/posting-json-to-a-web-service-with-php/#comments Fri, 01 Feb 2013 07:54:13 +0000 http://www.robertprice.co.uk/robblog/?p=1416 Continue reading "POSTing JSON To A Web Service With PHP"]]> I needed to POST JSON formatted data to a RESTful web service using PHP earlier, so I thought I’d share my solution.

There are a couple of approaches that could be taken, using the CURL extension, or file_get_contents and a http context. I took the later way.

When POSTing JSON to a RESTful web service we don’t send post fields or pretend to be a form, instead we have to send the JSON data in body of the request, and let the web service know it’s JSON data by setting the Content-type header to application/json.

$article = new stdClass();
$article->title = "An example article";
$article->summary = "An example of posting JSON encoded data to a web service";

$json_data = json_encode($article);

$post = file_get_contents('http://localhost/rest/articles',null,stream_context_create(array(
    'http' => array(
        'protocol_version' => 1.1,
        'user_agent'       => 'PHPExample',
        'method'           => 'POST',
        'header'           => "Content-type: application/jsonrn".
                              "Connection: closern" .
                              "Content-length: " . strlen($json_data) . "rn",
        'content'          => $json_data,
    ),
)));

if ($post) {
    echo $post;
} else {
    echo "POST failed";
}

Here I’m first creating an example PHP stdClass object, populating it with some data, then serialising it to a JSON string. The real magic is using file_get_contents to POST it over HTTP to my test web service. If the POST succeeds, then it’s displayed, else an error message is shown.

It’s important to note I send the header, Connection: close . Without this, your script will hang until the web server closes the connection. If we include it, then as soon as the data has POSTed the connection is closed and control returned to the script.

]]>
http://www.robertprice.co.uk/robblog/posting-json-to-a-web-service-with-php/feed/ 8