A single file PHP script which serves public posts to a Google Plus account as an Atom feed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* gplusatom.php | |
* | |
* A single file PHP script which serves public posts to a Google Plus account as an Atom feed. | |
* | |
* To use: | |
* 1) Obtain a google API key here https://code.google.com/apis/console | |
* 2) Fill in the 3 pieces of setup detail below. | |
* 3) Serve chilled | |
* | |
* Google really ought to provide this themselves in the API. | |
* If you agree, please go here, like the request and add some comment | |
* http://code.google.com/p/google-plus-platform/issues/detail?id=139 | |
* | |
* @author Julian Bond <julian_bond@voidstar.com> | |
* @version 0.002 | |
* @license 100% FREE TO COPY/USE FOR ANY PURPOSE, BUT DON'T BUG ME ABOUT IT, EVER. | |
* | |
* 31 October 2012 | |
*/ | |
$user_plus_id = 'CHANGE_ME'; // The ~21 digit number from your G Plus profile page | |
$google_api_key = 'CHANGE_ME'; // The ~40 char API key from Google | |
$user_full_name = 'CHANGE_ME'; // Used in the Feed Description | |
$max_results = 10; | |
$api_url = 'https://www.googleapis.com/plus/v1/people/'.$user_plus_id; | |
$api_url .= '/activities/public?key='.$google_api_key.'&maxResults='.$max_results; | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, $api_url); | |
curl_setopt($ch, CURLOPT_HEADER, false); | |
curl_setopt($ch, CURLINFO_HEADER_OUT, true); | |
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | |
curl_setopt($ch, CURLOPT_TIMEOUT, 15); | |
$response = curl_exec($ch); | |
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
$info = curl_getinfo($ch); | |
$error = curl_error($ch); | |
$errno = curl_errno($ch); | |
curl_close($ch); | |
if ($code != 200) { | |
echo 'Error' . PHP_EOL; | |
echo $code . PHP_EOL; | |
print_r($response); | |
print_r($info); | |
} else { | |
$all = json_decode($response); | |
$title = 'Google ' . $all->title; | |
$updated = date(DATE_ATOM, strtotime($all->updated)); | |
$link = 'https://plus.google.com/' . $user_plus_id . '/posts'; | |
header('Content-type: application/atom+xml; charset=UTF-8', true); | |
echo '<?xml version="1.0" encoding="utf-8"?' . '>' . PHP_EOL; | |
echo '<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>' . PHP_EOL; | |
echo '<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" '; | |
echo ' xmlns:georss="http://www.georss.org/georss" >'."\n"; | |
echo '<title>' . $title . '</title>'."\n"; | |
echo '<id>' . $all->id . '</id>'."\n"; | |
echo '<link type="text/html" rel="alternate" href="' . $link . '" />'."\n"; | |
echo '<link type="application/atom+xml" rel="self" href="http://' . $_SERVER[SERVER_NAME].$_SERVER[REQUEST_URI] . '" />'."\n"; | |
echo '<updated>' . $updated . '</updated>'."\n"; | |
echo '<subtitle>Google Plus posts from ' . $user_full_name . '.</subtitle>'."\n"; | |
foreach($all->items as $item) { | |
$id = $item->id; | |
$url = $item->url; | |
$published = date(DATE_ATOM, strtotime($item->published)); | |
$updated = date(DATE_ATOM, strtotime($item->updated)); | |
// Create Content | |
$post_content = ''; | |
if ($item->verb == 'share' && $item->annotation) { | |
$post_content .= $item->annotation . "\n"; | |
} | |
if ($item->verb == 'share') { | |
$post_content .= '<hr /><div><img src="'.$item->object->actor->image->url.'" style="padding-right:5px;float:left;" /></div>'; | |
$post_content .= '<div><a href="' . $item->object->actor->url . '">' . $item->object->actor->displayName . '</a> originally shared this <a href="' . $item->object->url . '">post</a>:<br />'; | |
} | |
if ($item->object->content != '') { | |
$post_content .= $item->object->content; | |
} | |
if ($item->verb == 'share') { | |
$post_content .= '</div><br style="clear:left" />'; | |
} | |
if ($item->object->attachments) { | |
foreach ($item->object->attachments as $attachment) { | |
$post_content .= '<hr />'; | |
if ($attachment->objectType == 'article') { | |
// get the thumbnail photo from the activity for the share | |
if ($item->object->attachments[1]->objectType == 'photo') { | |
$post_content .= '<div><a href="' . $attachment->url . '"><img src="' . $item->object->attachments[1]->image->url . '" style="padding-right:10px;float:left;" /></a></div>'; | |
} else if ($attachment->image) { | |
$post_content .= '<div><a href="' . $attachment->url . '"><img src="' . $attachment->image->url . '" style="padding-right:10px;float:left;" /></a></div>'; | |
} | |
$post_content .= '<div>'; | |
//construct favicon for the source website of the share | |
$host = ''; | |
if ($host = parse_url($attachment->url,PHP_URL_HOST) ) { | |
$post_content .= '<img src="https://s2.googleusercontent.com/s2/favicons?domain=' . urlencode($host) . '" style="padding-right:5px" />'; | |
} | |
//Create a title and link to the shared item | |
$post_content .= '<a href="' . $attachment->url . '">' . $attachment->displayName . ' >></a><br />'; | |
if ($attachment->content) { | |
$post_content .= $attachment->content. "\n"; | |
} | |
$post_content .= '</div>'; | |
break; | |
} | |
if ($attachment->objectType == 'photo') { | |
$post_content .= '<a href="' . $attachment->url . '"><img src="' . $attachment->image->url . '" /></a>'; | |
} | |
if ($attachment->objectType == 'video') { | |
if ($attachment->embed->url && stristr($attachment->embed->url,'youtube.com') ) { | |
$post_content .= "\n" . '<iframe width="560" height="315" src="' . $attachment->embed->url . '" frameborder="0" allowfullscreen></iframe>'; | |
} else if ($attachment->url && $attachment->image->url) { | |
$post_content .= "\n" . '<a href="' . $attachment->url . '"><img src="' . $attachment->image->url . '" /></a>'; | |
} else if ($video_embed = create_video_embed($attachment->url)) { | |
$post_content .= "\n" . $video_embed; | |
} | |
} | |
} | |
} //Item Attachments | |
//Item Location | |
$georss_content = ''; | |
if ($item->geocode) { | |
$coordinates = explode(' ',$item->geocode); | |
$gm_coordinates = implode(',',$coordinates); | |
$geo_cordinates = implode(' ',$coordinates); | |
$georss_content = " <georss:point>" . $geo_cordinates . "</georss:point>\n"; | |
$post_content .= "\n".'<br /><a href="http://maps.google.com/?ll=' . $gm_coordinates . '&q=' . $gm_coordinates . '"><img src="http://maps.googleapis.com/maps/api/staticmap?center=' . $gm_coordinates . '&zoom=12&size=75x75&maptype=roadmap&markers=size:small|color:red|' . $gm_coordinates . '&sensor=false"></a>'; | |
} | |
if ($item->placeName) { | |
$post_content .= "<br />\n" . $item->placeName; | |
} | |
if ($item->address) { | |
$post_content .= "<br />\n" . '<a href="http://maps.google.com/?ll=' . $gm_coordinates . '&q=' . $gm_coordinates . '">' . $item->address . '</a>'; | |
} | |
//wrapping the content in CDATA can avoid some XML character set problems. | |
$post_content = '<![CDATA['.htmlspecialchars($post_content).']]>'; | |
// $post_content = htmlspecialchars($post_content); | |
// Create title | |
$post_title = ''; | |
$post_title = $item->title; | |
// If there's no title get the name of anything attached | |
if ( $post_title == '' && $item->object->attachments[0]->displayName ) { | |
$post_title = $item->object->attachments[0]->displayName; | |
} | |
// Get only the first line of the title | |
$post_title = explode("\n", $post_title); | |
$post_title = $post_title[0]; | |
// Shorten title if it's too long | |
$max_characters = 255; | |
if (strlen($post_title)>$max_characters) { | |
preg_match('/(.{' . $max_characters . '}.*?)\b/', $post_title, $matches); | |
if ( strlen(rtrim($matches[1])) < strlen($post_title) ) { | |
$post_title = rtrim($matches[1]) . "..."; | |
} | |
} | |
$post_title = htmlspecialchars($post_title); | |
$authorName = $item->actor->displayName; | |
$authorUrl = $item->actor->url; | |
$authorImageUrl = $item->actor->image->url; | |
//Output the item entry | |
echo '<entry>'."\n"; | |
echo ' <title>' . $post_title . '</title>'."\n"; | |
echo ' <content type="html">' . $post_content . ' </content>'."\n"; | |
echo ' <id>' . $id . '</id>'."\n"; | |
echo ' <published>' . $published . '</published>'."\n"; | |
echo ' <updated>' . $updated . '</updated>'."\n"; | |
echo ' <link type="text/html" rel="alternate" href="' . $url . '"/>'."\n"; | |
echo ' <link type="image/png" rel="image" href="' . $authorImageUrl . '"/>'."\n"; | |
echo ' <author>'."\n"; | |
echo ' <name>' . $authorName . '</name>'."\n"; | |
echo ' <uri>' . $authorUrl . '</uri>'."\n"; | |
echo ' </author>'."\n"; | |
echo $georss_content; | |
echo '</entry>'."\n"; | |
} | |
echo '</feed>."\n"'; | |
} | |
// ******************* | |
function create_video_embed($swf_url) { | |
preg_match('#http://www\.youtube\.com/watch\?v=([A-Za-z0-9\-_]+)#s', $swf_url, $matches); | |
if (isset($matches[1])) { | |
$content .= '<iframe width="560" height="315" src="http://www.youtube.com/embed/'.$matches[1].'" frameborder="0" allowfullscreen></iframe>'; | |
return $content; | |
} else { | |
preg_match('#http://w?w?w?.?vimeo.com/moogaloop.swf\?clip_id=([A-Za-z0-9\-_]+)&#s', $swf_url, $matches); | |
if (isset($matches[1])) { | |
return "http://www.vimeo.com/".$matches[1]; | |
} else if (!isset($matches[1])) { | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment