This week I received some reports that the Magic Mirror calendar section stopped working. Since the mirror gracefully hides the calendar data, I didn’t really notice it on my own Magic Mirror. Of course, this must be fixed.
To figure out what was wrong, I started with the feed url. When I entered this in my browser, the .ical file was correctly downloaded, and after opening, it seems to look fine …
The next step in the calendar display process is the proxy script: calendar.php, since an Ajax request direct to the iCloud servers is not permitted. After opening this calendar.php file in my browser, the issue was visible: it only shows some useless coded garbish.
Somehow, the feed could not be correctly downloaded by the calendar.php. Till now, this was done, using the following line:
echo file_get_contents($url);
Since, the file_get_contents
isn’t very sophisticated, I tried switching to curl:
<?php
// Set the url of the calendar feed.
$url = 'https://p01-calendarws.icloud.com/ca/subscribe/1/...';
// Initialize the curl request.
$ch = curl_init();
// Set the CURL url.
curl_setopt ($ch, CURLOPT_URL, $url);
// Make sure redirects are followed.
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true);
// Execute the request and echo the response.
echo curl_exec($ch);
// Close the CURL request.
curl_close($ch);
Unfortunately, this still gave the same result. So time to dive in the CURL documentation. CURL has a lots of options that can be set by above used curl_setopt()
function. So chances are, a solution is hidden within these options.
After some reading, I found the CURLOPT_ENCODING option:
The contents of the “Accept-Encoding: ” header. This enables decoding of the response. Supported encodings are “identity”, “deflate”, and “gzip”. If an empty string, “”, is set, a header containing all supported encoding types is sent.
After setting this flag to true, the script outputted the desired format. Setting the flag before the echo was simple:
curl_setopt ($ch, CURLOPT_ENCODING, true);
It seems Apple recently turned on gzip compression on their iCal webservers.
Unfortunately, after testing it on my actual Raspberry Pi, I found out that my PHP installation on my RPi does not support CURL. But since I now found the reason and solution, some googling brought me to a post on BinaryTides which shows a file_get_contents()
way to use decoding. Using this solution, I now got my calendar up and running again, using the following code:
<?php
// Set the url of the calendar feed.
$url = 'https://p01-calendarws.icloud.com/ca/subscribe/...';
/*****************************************/
// Run the helper function with the desired URL and echo the contents.
echo get_url($url);
// Define the helper function that retrieved the data and decodes the content.
function get_url($url)
{
//user agent is very necessary, otherwise some websites like google.com wont give zipped content
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-Language: en-US,en;q=0.8rn" .
"Accept-Encoding: gzip,deflate,sdchrn" .
"Accept-Charset:UTF-8,*;q=0.5rn" .
"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0 FirePHP/0.4rn"
)
);
$context = stream_context_create($opts);
$content = file_get_contents($url ,false,$context);
//If http response header mentions that content is gzipped, then uncompress it
foreach($http_response_header as $c => $h)
{
if(stristr($h, 'content-encoding') and stristr($h, 'gzip'))
{
//Now lets uncompress the compressed data
$content = gzinflate( substr($content,10,-8) );
}
}
return $content;
}
Of course, this fix is included in the Magic Mirror Repository on GitHub.
Man, it feels good if you solve a bug! :)