An Eclectic World Recode: Adding a Flickr Gallery


Part of the purpose of my website is to be a sort of central site branching off to my social media presences, other sites, and things like my Flickr account.  As such, I have a feed of my most recent blog posts and Flickr uploads featured on the front page.  I also pull in pics from their specific albums for each of my girls’ profile pages.

I wanted to keep this going with the recode, and as I’m working on the core application structure, that was one of my first things to look at.  My old ColdFusion site just used the RSS feed, which was a limited and dated way to do so.  But I wanted to do a better app, and instead properly use the full Flickr API to pull in my content in PHP.

Being as it is a Zend app, I first looked at the built-in Zend Flickr API.   It was disappointing, to say the least.  Extremely limited functionality, and with seemingly no presumption that the primarily users might be people wanting to pull in their own photos and having a user ID, versus doing an email or tag search.

So I dismissed it and flipped to just coding it in straight PHP, within a service, using cURL.  This opens up the entire range of functionality from Flickr’s impressive API.  To get started, I acquired a Flickr API Key, which takes just a few moments via their form.  I already had my numeric Flickr user ID (not the same as your username), but if you don’t have yours:

  • Go to your Photostream
  • Hit Edit under the “More” menu
  • Scroll to the bottom, where “Subscribe to [username]’s Photostream, sits and click on Latest
  • Your user ID is in the URL, the ID parameter
    https://api.flickr.com/services/feeds/photos_public.gne?id=[ID]&lang=en-us&format=rss_200

After skimming the API documentation, I found the function I wanted for my home page pull, flickr.people.getPublicPhotos (I could also just use getPhotos since I’d only be pulling public either way).

After that, the code to create my Flickr Service was pretty simple and straightforward, beefed up just a bit to have nice error handling/notification. My API key and user ID are set in my config, for cleaner code and fewer places to hunt for such things. I could move the Flickr API url there too, but for now, here it is:

<?php
	namespace Application\Service;
	
	use Zend\ServiceManager\ServiceLocatorAwareInterface;
	
	class FlickrService implements ServiceLocatorAwareInterface {
		protected $serviceLocator;
		
		protected $default_num_pics = 10;
		protected $default_display_size = 'm';
		protected $aValidSizes = array('sq','t','s','q','m','n','z','c','l');
	
		public function __construct() {}
		
		public function getPics($num_pics = 10, $display_size = NULL, $from_set = NULL) {
			$result_code = 200;
			$result_message = "";
			$aPhotos = array();

			try{
				$aConfig = $this->getServiceLocator()->get('config');
				$aFlickrConfig = $aConfig['flickr'];
				
				// sanity check, make sure we have a valid display size and pic number; Flickr TOS says no more than 30 per request, so enforce that too
				if($num_pics < 1 || $num_pics > 30)
					$num_pics = $this->default_num_pics;
					
				if(!array_search($display_size, $this->aValidSizes) == -1)
					$display_size = $this->default_display_size;
				
				// set up our call; depending on who is calling, we're getting from photo stream or a specified set
				if(empty($from_set))
					$method = 'flickr.people.getPublicPhotos';
				else
					$method = 'flickr.photosets.getPhotos';
				
				$aParameters = array(
					'method' => $method,
					'user_id' => $aFlickrConfig['user_id'],
					'api_key' => $aFlickrConfig['api_key'],
					'per_page' => $num_pics,
					'format' => 'json',
					'nojsoncallback' => 1,
					'extras' => 'date_upload, date_taken, url_sq, url_t, url_s, url_q, url_m, url_n, url_z, url_c, url_l',
				);
				
				if(!empty($from_set))
					$aParameters['photoset_id'] = $from_set;
				
				$flickr_api_url = "https://api.flickr.com/services/rest/?" . http_build_query($aParameters);
				
				// make the actual call, via curl
				$doCurl = curl_init();
				curl_setopt($doCurl, CURLOPT_URL, $flickr_api_url);
				curl_setopt($doCurl, CURLOPT_RETURNTRANSFER, 1);
				$curl_response = curl_exec($doCurl);
				
				$aDebugInfo = curl_getinfo($doCurl);
				$aFlickrResponse = json_decode($curl_response);
	
				curl_close ($doCurl);
				
				// confirm we have a response, and if so process
				if($curl_response && $aFlickrResponse && $aFlickrResponse->stat == 'ok'):
					// the resonse comes back as a payload of objects, but we really just care about the photos
					$oPhotos = $aFlickrResponse->photos->photo;
				
					foreach($oPhotos as $oThisPhoto):
						$aPhotos[] = array(
							'title' => $oThisPhoto->title,
							'date_uploaded' => date('F, j, Y, g:i a', $oThisPhoto->dateupload),
							'date_taken' => date('F, j, Y, g:i a', strtotime($oThisPhoto->datetaken)),
							'height' => $oThisPhoto->{"height_" . $display_size},
							'width' => $oThisPhoto->{"width_" . $display_size},
							'url' => $oThisPhoto->{"url_" . $display_size},
							'thumbnail' => $oThisPhoto->url_t, // in addition to the requested size, always get the thumbnail too
						);
					endforeach;
				
				else:
					$result_code = 300;
					
					if(!$curl_response)
						throw(curl_error($doCurl));
					
					elseif($aFlickrResponse->stat != 'ok')
						throw(curl_error($aFlickrResponse->message));
					
					elseif($aDebugInfo['http_code'] != 200)
						$result_message = "Unable to reach Flickr API";
						
				endif;
			}
			catch (\Exception $e) {
				$this->oErrorHandlingService->handleAppError($e);
			
				$result_code = 300;
				$result_message = 'System error occurred.  The webmaster has been notified.';
			}
			
			$aResults = array(
				'result_code' => $result_code,
				'result_message' => $result_message,
				'aPhotos' => $aPhotos,
			);
			
			return $aResults;
		}

		public function getServiceLocator() {
			return $this->serviceLocator;
		}
	
		public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
			$this->serviceLocator = $serviceLocator;
		}
	}
?>

Then on the front end, I can loop through my results and make a nice photo display.  I decided to use Unite Gallery for a nice presentation. The controller, of course, calls the services and sends the results to the view. For the display side, we have:

<?php
	$this->layout()->pageTitle = "Welcome to An Eclectic World!";
	$this->layout()->activeMenu = 'home';
	$this->layout()->needUnite = true;
?>

<p>This is the personal website of myself, Summer. It's been online in some form or another since 1995, making it one of the oldest sites still on the Internet!</p>
<p>Personal sites have, alas, gone "out of style", but I love my little site, so I'm keeping it around. These days it serves three primary functions: 
its the home for my online catalogs of all of my media (books, movies/tv series, and video games), it has nice little intros to myself & my family,
and it acts as a sort of "central hub" to find my other sites and social profiles around the Internet.</p>

	<?php if($aFlickrFeed['result_code'] == 200): ?>
		<h3 class="text-center"><a href="http://www.flickr.com/photos/collectonian/" target="_blank">My Recent Photos on Flickr</a></h3>	
	
		<div id="flickrFeed" class="hide-on-load center-block">
			<?php foreach($aFlickrFeed['aPhotos'] as $key => $aThisPhoto): ?>
				<img 
					alt="<?php echo $aThisPhoto['title']; ?>"
					src="<?php echo $aThisPhoto['thumbnail']; ?>"
					data-image="<?php echo $aThisPhoto['url']; ?>"
					data-description="<?php echo $aThisPhoto['date_taken']; ?>"
					>
			<?php endforeach; ?>
		</div>
	<? endif; ?>

<?php $this->inlineScript()->captureStart(); ?>
	jQuery("#flickrFeed").unitegallery({
		gallery_theme: "compact",
		thumb_border_effect: false,
		thumb_color_overlay_effect: true,
		thumb_overlay_color: "#ffffff",
		thumb_overlay_reverse: false,
		thumb_overlay_opacity: 0.5,
		slider_enable_text_panel: true,
		strippanel_enable_handle: false,
		slider_control_zoom: false,
		slider_scale_mode: "fit",
		slider_enable_progress_indicator:false,
		slider_enable_zoom_panel:false,
		slider_enable_text_panel:false,
		strippanel_enable_handle:false,
		gridpanel_enable_handle:false,
	});
<?php $this->inlineScript()->captureEnd(); ?>

And, so far looking pretty nice!An Eclectic World Recode: Front Page With Flickr