July 11, 201214 yr I've been busy creating a website for a friend, all is good except from I have implemented a videos pod on the homepage which allows users to watch the latest videos from a YouTube playlist. But this is grabbed from YouTube's servers every time the page is loaded, how can I set something up so new videos are only checked for every... hour? I tried using this to cache it, appeared to be working fine until it got an hour old and the cache had to be refreshed but for some reason it didn't work so after an hour the script would return blank. http://papermashup.com/caching-dynamic-php-pages-easily/ The page I'm trying to get it working on is at http://charlieswebsites.co.uk/fearofmobs/site/, in the videos pod (be aware that the videos here are static, but the code below is what I WAS using) The code I used is below: HTML HEADER AND CONTENT LEADING UP TO VIDEOS POD IS HERE <?php $cachefile = 'videos.php'; $cachetime = 60 * 60; // Serve from the cache if it is younger than $cachetime if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) { include($cachefile); echo "<!-- Cached copy, generated ".date('H:i', filemtime($cachefile))." -->\n"; } ob_start(); // Start the output buffer ?> ALL REMAINING CONTENT, INCLUDING FOOTER, SIDEBAR ETC. <?php exit; // Cache the contents to a file $cached = fopen($cacheFile, 'w'); fwrite($cached, ob_get_contents()); fclose($cached); ob_end_flush(); // Send the output to the browser ?> The contents of video.php is: <div id="videos" class="pod"><h3>Videos</h3><p class="homepod-intro">Explore the <a id="playlist-link" href="http://www.youtube.com/playlist?list=PLC82EBDAC0429B6A2">Fear of Mobs playlist</a>, click on a video!</p> <?php get_playlists(); function get_playlists(){ $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); $xml = simplexml_load_string($data); foreach($xml->entry as $playlist){ $media = $playlist->children('http://search.yahoo.com/mrss/'); $attrs = $media->group->thumbnail[1]->attributes(); $thumb = $attrs['url']; $attrs = $media->group->player->attributes(); $video = $attrs['url']; $title = substr( $media->group->title, 27); $url = $video; parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars ); $vid_Id = $my_array_of_vars['v']; $thumbnail .= '<div style="float:left; cursor:pointer;"> <p class="crop"><a class="videobox various iframe" href="http://www.youtube.com/embed/' . $vid_Id . '?autoplay=1&hd=1"><img src="' .$thumb . '" title="' . $title . '" width="74" height="56"/></a></p></div>'; }print $thumbnail;} ?> </div> Any help would be so appreciated, I've been tinkering for hours! Edited July 11, 201214 yr by Charlie
July 11, 201214 yr Write the data from.. $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); to the server as ordinary 'flat' file like a text file and call it video_temp.txt . It's this file that the cache script needs to read the filetime for and fetch again if older than one hour. This is untested but looks about right, the video.php will need to changed so that instead of using file_get_contents it just reads the video_temp.txt file.. $cachefile = 'video_temp.txt'; $cachetime = 60 * 60; // Use exisiting copy if younger than $cachetime if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) { /// do nothing because not enough time has elapsed /// the video.php script will read exisiting video_temp.txt file } else { // go get latest results $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); // overwrite video_temp.txt with new information $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh) // now when video.php requests that file it sees new information } Edited July 11, 201214 yr by Sogo7
July 11, 201214 yr Author Hi, thank you for your response! I've updated the site with the code you provided but I think I've implemented it wrong , I've added the last snippet of code you provided in the index.php in the place I'd want the videos to be displayed (currently live at the url in original post). And left the videos.php as is, with the script that pulls in the videos. I've also created the empty video_temp.php file for caching, have I done something wrong? Thanks! Edited July 11, 201214 yr by Charlie
July 11, 201214 yr Here you go... plus a couple of refinements that I think you may like. It caches the playlist plus saves the images to the sites server so the menu no longer hotlinks to YouTube for them and clicking toggles the video to be shown inside the web page. live demo at http://lovelogic.net/z_tuts/charlie_demo.php# <?php $cachefile = 'video_temp.txt'; // Use exisiting copy if younger than $cachetime $cache_timer = 3600 + @filemtime($cachefile);// files timestamp + 3600 seconds //echo 'CacheTime -> '.$cache_timer . ' | CurrentTime ->'.time()."<br>"; if (file_exists($cachefile) && time() < $cache_timer ) { //echo "no update <br>"; } else { //echo "doing update <br>"; // go get latest results $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); // overwrite video_temp.txt with new information $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); } /////////////////////////////////////////// Build image menu $data = file_get_contents($cachefile); $xml = simplexml_load_string($data); foreach($xml->entry as $playlist){ $media = $playlist->children('http://search.yahoo.com/mrss/'); $attrs = $media->group->thumbnail[1]->attributes(); $thumb = $attrs['url']; $attrs = $media->group->player->attributes(); $video = $attrs['url']; $title = substr( $media->group->title, 27); $url = $video; parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars ); $vid_Id = $my_array_of_vars['v']; ///////////////// Save Images To Local Webserver //////////////// just in case Youtube objects to hotlinking $image_ID = $vid_Id.".jpg"; /// or use sub folder for neatness like so "images_folder/".$vid_Id.".jpg" $image_saved = @filemtime($image_ID);// @ is used to suppress the error caused by the image or file not having been saved yet if (!$image_saved){/// if you can't find it on local server go fetch it and save to the sites server file_put_contents($image_ID, file_get_contents($thumb)); }//// close if image saved ///// thumbnail image now comes from the sites server and not hotlinked to YouTube ///// $thumb [url pointing to YouTube] has been replaced with $image_ID that links to locally stored file $thumbnail .= '<div style="float:left; cursor:pointer;"> <p class="crop"><a class="videobox various iframe" href="#" onclick=swapper("'. $vid_Id .'")><img src="' .$image_ID . '" title="' . $title . '" width="74" height="56"/></a></p></div>'; }// end foreach as playlist loop ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Untitled Document</title> <style> #pump { float:left; background-color:#003399; width:560px; height:349px; background-image:url(http://lovelogic.net/z_tuts/Testcard_F.jpg); background-repeat: no-repeat; background-position: center center; } </style> <script type="text/javascript"> function swapper(videoRef){ var frame = '<iframe class=\"embeddedvideo\" src=\"http://www.youtube-nocookie.com/v/'+videoRef+'?version=3&hl=en_GB&rel=0\" type=\"application/x-shockwave-flash\" width=\"560\" height=\"349\"></iframe>'; var curtextval = document.getElementById("pump"); curtextval.innerHTML = (frame); } </script> </head> <body><h3>Click an image to watch video</h3> <?php echo $thumbnail; ?> </div> <div id="pump"></div> </body> </html> Edited July 11, 201214 yr by Sogo7
July 11, 201214 yr Author Thank you so much for all of your help, you can see how I've implemented at the hyperlink in my original post. Also one more question (sorry!), I'm going to be displaying summaries of blog posts from a tumblr using the following PHP code, how would I do the exact same thing (caching every hour) with that peice of code? <?php $request_url = "http://deaboy.tumblr.com/api/read?type=post&start=0&num=1"; $xml = simplexml_load_file($request_url); $title = $xml->posts->post->{'regular-title'}; $post = $xml->posts->post->{'regular-body'}; $link = $xml->posts->post['url']; $small_post = substr($post,0,320); echo '<h1>'.$title.'</h1>'; echo '<p>'.$small_post.'</p>'; echo "…"; echo "</br><a target=frame2 href='".$link."'>Read More</a>"; ?> Again, thank you so much! Edited July 11, 201214 yr by Charlie
July 12, 201214 yr That works pretty good on the site, nice effect. <?php $cachefile_blog = 'blog_temp.txt'; $cache_timer = 3600 + @filemtime($cachefile);// files timestamp + 3600 seconds if (file_exists($cachefile) && time() < $cache_timer ) { // do nothing if file is fresh } else { // go get latest results $data = file_get_contents("http://deaboy.tumblr.com/api/read?type=post&start=0&num=1"); // overwrite the cached file with new data $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); } // read the cached file $request_url = file_get_contents($cachefile_blog); $xml = simplexml_load_file($request_url); $title = $xml->posts->post->{'regular-title'}; $post = $xml->posts->post->{'regular-body'}; $link = $xml->posts->post['url']; $small_post = substr($post,0,320); echo '<h1>'.$title.'</h1>'; echo '<p>'.$small_post.'</p>'; echo "…"; echo "</br><a target=frame2 href='".$link."'>Read More</a>"; ?>
July 12, 201214 yr Author The blog code giving me an error of: Warning: simplexml_load_file() [function.simplexml-load-file]: I/O warning : failed to load external entity "" in /websites/123reg/LinuxPackage22/ch/ar/li/charlieswebsites.co.uk/public_html/fearofmobs/site/index.php on line 85 The code on line 85 is: $xml = simplexml_load_file($request_url); Also one more thing, could you tell me how to remove the part from the YouTube code that saves the thumbnails to local server as I think it's actually quicker grabbing those from YouTube directly? I tried removing that section of the code but it didn't work . Again thank you so much for your help! Do you have a donation page setup anywhere? Edited July 12, 201214 yr by Charlie
July 12, 201214 yr My bad.. was a typo in the blog demo. This now works <?php $cachefile_blog = 'blog_temp.txt'; $cache_timer = 3600 + @filemtime($cachefile_blog);// files timestamp + 3600 seconds if (file_exists($cachefile_blog) && time() < $cache_timer ) { // do nothing if file is fresh } else { // go get latest results $data = file_get_contents("http://deaboy.tumblr.com/api/read?type=post&start=0&num=1"); // overwrite the cached file with new data $fh = fopen($cachefile_blog, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); } // read the cached file $request_url = file_get_contents($cachefile_blog); $xml = simplexml_load_string($request_url); ///simplexml_load_string --- for local files ///simplexml_load_file --- for URLS $title = $xml->posts->post->{'regular-title'}; $post = $xml->posts->post->{'regular-body'}; $link = $xml->posts->post['url']; $small_post = substr($post,0,320); echo '<h1>'.$title.'</h1>'; echo '<p>'.$small_post.'</p>'; echo "…"; echo "</br><a target=frame2 href='".$link."'>Read More</a>"; ?> I've ammended the image menu demo and put in variable called $toggle this will allow you to switch between saving images and hotlinking to YouTube by changing the value. Notes: $thumb .. is the Youtube image URL $image_ID .. is localy stored image URL Remember if you junk the image saving section of the script then the $thumbnail string builder needs to be changed as well with $image_ID replaced by $thumb. <?php $cachefile = 'video_temp.txt'; // Use exisiting copy if younger than $cachetime $cache_timer = 3600 + @filemtime($cachefile);// files timestamp + 3600 seconds //echo 'CacheTime -> '.$cache_timer . ' | CurrentTime ->'.time()."<br>"; if (file_exists($cachefile) && time() < $cache_timer ) { //echo "no update <br>"; } else { //echo "doing update <br>"; // go get latest results $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); // overwrite video_temp.txt with new information $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); } /////////////////////////////////////////// Build image menu $data = file_get_contents($cachefile); $xml = simplexml_load_string($data); foreach($xml->entry as $playlist){ $media = $playlist->children('http://search.yahoo.com/mrss/'); $attrs = $media->group->thumbnail[1]->attributes(); $thumb = $attrs['url']; $attrs = $media->group->player->attributes(); $video = $attrs['url']; $title = substr( $media->group->title, 27); $url = $video; parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars ); $vid_Id = $my_array_of_vars['v']; ###################NEW CODE $toggle = 'hotlink';// replace 'hotlink' with 'null' to save images locally if ($toggle == 'hotlink'){ $image_ID = $thumb; // hotlink images from YouTube } else{ ///////////////////////////////// Save Images To Local Webserver ///////////////////////////////// just in case Youtube objects to hotlinking $image_ID = $vid_Id.".jpg"; /// or use sub folder for neatness -> "images_folder/".$vid_Id.".jpg" $image_saved = @filemtime($image_ID);// @ is used to suppress the error caused by the image not having been seen before if (!$image_saved){/// if you can't find it on local server go fetch it and save to the sites server file_put_contents($image_ID, file_get_contents($thumb)); //// you can delete the line below echo ' fecthed image >> '.$image_ID."<br>" ; //// you can delete the line above }//// close if image saved } ##################### END NEW CODE ///// thumbnail image now comes from the sites server and not hotlinked to YouTube ///// $thumb [url pointing to YouTube] has been replaced with $image_ID that links to locally stored file $thumbnail .= '<div style="float:left; cursor:pointer;"> <p class="crop"><a class="videobox various iframe" href="#" onclick=swapper("'. $vid_Id .'")><img src="' .$image_ID . '" title="' . $title . '" width="74" height="56"/></a></p></div>'; }// end foreach as playlist loop ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Untitled Document</title> <style> #pump { float:left; background-color:#003399; width:560px; height:349px; background-image:url(http://lovelogic.net/z_tuts/Testcard_F.jpg); background-repeat: no-repeat; background-position: center center; } </style> <script type="text/javascript"> function swapper(videoRef){ var frame = '<iframe class=\"embeddedvideo\" src=\"http://www.youtube-nocookie.com/v/'+videoRef+'?version=3&hl=en_GB&rel=0\" type=\"application/x-shockwave-flash\" width=\"560\" height=\"349\"></iframe>'; var curtextval = document.getElementById("pump"); curtextval.innerHTML = (frame); } </script> </head> <body><h3>Click an image to watch video</h3> <?php echo $thumbnail; ?> </div> <div id="pump"></div> </body> </html> There is always going to a small delay when fetching and saving files into a 'live' page using this method. You may at some later date want to look at using a Cron job to test the age of the cached files (updating if needed) as this will run independantly of the actual webpage as a background task. So the page never has to wait for file_get_contents to finish running before loading. Edited July 12, 201214 yr by Sogo7
July 12, 201214 yr Author Oh, one more tiny thing (sorry, I promise this is the last thing!) The end of the blog summaries (check link in original post) get cut off, I added text-overflow:ellipsis in CSS which makes it looks slightly better, but how can i cut it off at the nearest word? For example call more characters then I need and then cut off to the nearest wood to 132 characters and append a …? A small thing I know!
August 8, 201214 yr Author Hi Sogo, the script has stopped working for me recently, is it still working for you? I'm getting errors with it now, I've moved to a new host if that makes a difference, I've got it running separately at http://new.fearofmobs.com/playlist.php Errors are: Warning: simplexml_load_file(): videobrowser.txt:1: parser error : Document is empty in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: simplexml_load_file(): in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: simplexml_load_file(): ^ in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: simplexml_load_file(): videobrowser.txt:1: parser error : Start tag expected, '<' not found in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: simplexml_load_file(): in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: simplexml_load_file(): ^ in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 16 Warning: Invalid argument supplied for foreach() in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/playlist.php on line 18 Any help greatly appreciated, the code for the page is: <?php error_reporting(E_ALL ^ E_NOTICE); ini_set('display_errors', 1);?> <?php $cachefile = 'videobrowser.txt'; $cache_timer = 3600 + @filemtime($cachefile);// files timestamp + 3600 seconds if (file_exists($cachefile) && time() < $cache_timer ) { } else { $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); } $thumbnail =''; $data = simplexml_load_file($cachefile); $xml = simplexml_load_string($data); foreach($xml->entry as $playlist){ $media = $playlist->children('http://search.yahoo.com/mrss/'); $attrs = $media->group->thumbnail[1]->attributes(); $thumb = $attrs['url']; $attrs = $media->group->player->attributes(); $video = $attrs['url']; $title = substr( $media->group->title, 21); $url = $video; parse_str( parse_url( $url, PHP_URL_QUERY ), $my_array_of_vars ); $vid_Id = $my_array_of_vars['v']; ###################NEW CODE $toggle = 'hotlink';// replace 'hotlink' with 'null' to save images locally if ($toggle == 'hotlink'){ $image_ID = $thumb; // hotlink images from YouTube } else{ ///////////////////////////////// Save Images To Local Webserver ///////////////////////////////// just in case Youtube objects to hotlinking $image_ID = $vid_Id.".jpg"; /// or use sub folder for neatness -> "images_folder/".$vid_Id.".jpg" $image_saved = @filemtime($image_ID);// @ is used to suppress the error caused by the image not having been seen before if (!$image_saved){/// if you can't find it on local server go fetch it and save to the sites server file_put_contents($image_ID, file_get_contents($thumb)); //// you can delete the line below echo ' fecthed image >> '.$image_ID."<br>" ; //// you can delete the line above }//// close if image saved } ##################### END NEW CODE $thumbnail .= '<div style="float:left; cursor:pointer;"> <p class="crop"><a class="videobox various iframe" href="http://www.youtube.com/embed/' . $vid_Id . '?autoplay=1&hd=1" onclick=swapper('. $vid_Id .')><img src="' .$image_ID . '" title="' . $title . '" width="74" height="56"/></a></p></div>'; } ?> <?php echo $thumbnail; ?>
August 8, 201214 yr Sorry did not answer you sooner Charlie, one of the dogs has got himself kicked by the goat. Is it still throwing up an error? edit... leave it with me overnight I'll take a look Ok I have it .. $data = simplexml_load_file($cachefile); $xml = simplexml_load_string($data); Is where your alterations went adrift, in the attempt to remove a redundant line of code in the demo I did you've got the variables mixed up and added a line you don't need yourself. replace those two lines above with this one below. $xml = simplexml_load_file($cachefile); Edited August 8, 201214 yr by Sogo7
August 16, 201214 yr Author Hey Sogo, Thank you for continuing to help me with this & I hope your dog is well ! I've had the code fixed now but have come across another small error that I keep experiencing. It doesn't happen 24/7, just sometimes? I think it happens after I haven't visited the page for a while or maybe after it refreshes the cache after an hour? Getting this error in the videos pod here currently: Warning: file_get_contents(http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12): failed to open stream: HTTP request failed! HTTP/1.0 403 Forbidden in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 42 Warning: simplexml_load_file(): videobrowser.txt:1: parser error : Document is empty in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Warning: simplexml_load_file(): in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Warning: simplexml_load_file(): ^ in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Warning: simplexml_load_file(): videobrowser.txt:1: parser error : Start tag expected, '<' not found in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Warning: simplexml_load_file(): in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Warning: simplexml_load_file(): ^ in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 49 Notice: Trying to get property of non-object in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 50 Warning: Invalid argument supplied for foreach() in /hermes/waloraweb095/b2598/moo.fearofmobscom/fearofmobs2/index.php on line 50 This seems to be fixed (it is now) after visiting a few times? But it keeps reoccurring. The full code for that page can be found here. Thanks so much again, I need to tip you!!
August 30, 201214 yr Author Hi Sogo, Did you get a chance to take a look at this for me? Would really appreciate it! Thanks!
August 31, 201214 yr Looks like the YouTube api getting stuck at their end , try changing lines 42 to 45 from $data = file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh); to this $data = @file_get_contents("http://gdata.youtube.com/feeds/api/playlists/C82EBDAC0429B6A2?orderby=published&max-results=12"); if ($data){ $fh = fopen($cachefile, 'w') or die("can't open file"); fwrite($fh, $data); fclose($fh);} Whats changed.. the @ symbol will suppress the file_get_contents command from generating an error if YouTube cannot provide an answer to its request, script carries on with no information in the $data variable an IF statement around the code that writes the new $data to the server, so now only if the file_get_contents has worked and there is something in the $data variable does it write a new cache. That should keep it from misbehaving.
Create an account or sign in to comment