News:

Want to get involved in developing SMF, then why not lend a hand on our github!

Main Menu

Opinions on a banner rotator script.

Started by Antechinus, January 14, 2015, 02:46:19 PM

Previous topic - Next topic

Antechinus

I've been thinking about making a change to a feature on my new theme.

What I did initially was to hijack the SMF random news lines to create a banner change on page load. This was fun on a test site, livens up the testing time, and works just fine, but has the obvious disadvantages of a/ hijacking the SMF random news lines :D and b/ not being theme-specific.

So, obvious next step is to put the SMF stuff back to normal and think about incorporating a dedicated script to do the job, with theme-specific custom settings so different themes can run a different pack of banners (for instance, dark themes and light themes may want a different look up top).

I've checked the mod site and most of the banner flipping mods seem to use this free script: Marcofolio - PHP Random Image Rotation. This looks like it would do the job nicely if included in the theme.

What I'm wondering now is if, given what it does, this script is straightforward, secure and reasonably performant, or if there would be a markedly better way of doing the job.

Code is below, for convenience.

<?php

/*
DOWNLOADED FROM http://www.marcofolio.net/
Check it out for more interesting scripts & downloads

AUTOMATIC IMAGE ROTATOR
Version 2.2 - December 4, 2003
Copyright (c) 2002-2003 Dan P. Benjamin, Automatic, Ltd.
All Rights Reserved.

http://www.hiveware.com/imagerotator.php

http://www.automaticlabs.com/


DISCLAIMER
Automatic, Ltd. makes no representations or warranties about
the suitability of the software, either express or
implied, including but not limited to the implied
warranties of merchantability, fitness for a particular
purpose, or non-infringement. Dan P. Benjamin and Automatic, Ltd.
shall not be liable for any damages suffered by licensee
as a result of using, modifying or distributing this
software or its derivatives.


ABOUT
This PHP script will randomly select an image file from a
folder of images on your webserver.  You can then link to it
as you would any standard image file and you'll see a random
image each time you reload.

When you want to add or remove images from the rotation-pool,
just add or remove them from the image rotation folder.


VERSION CHANGES
Version 1.0
- Release version

Version 1.5
- Tweaked a few boring bugs

Version 2.0
- Complete rewrite from the ground-up
- Made it clearer where to make modifications
- Made it easier to specify/change the rotation-folder
- Made it easier to specify/change supported image types
- Wrote better instructions and info (you're them reading now)
- Significant speed improvements
- More error checking
- Cleaner code (albeit more PHP-specific)
- Better/faster random number generation and file-type parsing
- Added a feature where the image to display can be specified
- Added a cool feature where, if an error occurs (such as no
  images being found in the specified folder) *and* you're
  lucky enough to have the GD libraries compiled into PHP on
  your webserver, we generate a replacement "error image" on
  the fly.

    Version 2.1
        - Updated a potential security flaw when value-matching
          filenames

    Version 2.2
        - Updated a few more potential security issues
        - Optimized the code a bit.
        - Expanded the doc for adding new mime/image types.

        Thanks to faithful ALA reader Justin Greer for
        lots of good tips and solid code contribution!


INSTRUCTIONS
1. Modify the $folder setting in the configuration section below.
2. Add image types if needed (most users can ignore that part).
3. Upload this file (rotate.php) to your webserver.  I recommend
   uploading it to the same folder as your images.
4. Link to the file as you would any normal image file, like this:

<img src="http://example.com/rotate.php">

5. You can also specify the image to display like this:

<img src="http://example.com/rotate.php?img=gorilla.jpg">

This would specify that an image named "gorilla.jpg" located
in the image-rotation folder should be displayed.

That's it, you're done.

*/




/* ------------------------- CONFIGURATION -----------------------


Set $folder to the full path to the location of your images.
For example: $folder = '/user/me/example.com/images/';
If the rotate.php file will be in the same folder as your
images then you should leave it set to $folder = '.';

*/


$folder '.';


/*

Most users can safely ignore this part.  If you're a programmer,
keep reading, if not, you're done.  Go get some coffee.

    If you'd like to enable additional image types other than
gif, jpg, and png, add a duplicate line to the section below
for the new image type.

Add the new file-type, single-quoted, inside brackets.

Add the mime-type to be sent to the browser, also single-quoted,
after the equal sign.

For example:

PDF Files:

$extList['pdf'] = 'application/pdf';

    CSS Files:

        $extList['css'] = 'text/css';

    You can even serve up random HTML files:

    $extList['html'] = 'text/html';
    $extList['htm'] = 'text/html';

    Just be sure your mime-type definition is correct!

*/

    
$extList = array();
$extList['gif'] = 'image/gif';
$extList['jpg'] = 'image/jpeg';
$extList['jpeg'] = 'image/jpeg';
$extList['png'] = 'image/png';


// You don't need to edit anything after this point.


// --------------------- END CONFIGURATION -----------------------

$img null;

if (
substr($folder,-1) != '/') {
$folder $folder.'/';
}

if (isset(
$_GET['img'])) {
$imageInfo pathinfo($_GET['img']);
if (
    isset( $extListstrtolower$imageInfo['extension'] ) ] ) &&
        
file_exists$folder.$imageInfo['basename'] )
    ) {
$img $folder.$imageInfo['basename'];
}
} else {
$fileList = array();
$handle opendir($folder);
while ( false !== ( $file readdir($handle) ) ) {
$file_info pathinfo($file);
if (
    isset( $extListstrtolower$file_info['extension'] ) ] )
) {
$fileList[] = $file;
}
}
closedir($handle);

if (count($fileList) > 0) {
$imageNumber time() % count($fileList);
$img $folder.$fileList[$imageNumber];
}
}

if (
$img!=null) {
$imageInfo pathinfo($img);
$contentType 'Content-type: '.$extList$imageInfo['extension'] ];
header ($contentType);
readfile($img);
} else {
if ( function_exists('imagecreate') ) {
header ("Content-type: image/png");
$im = @imagecreate (100100)
    or die ("Cannot initialize new GD image stream");
$background_color imagecolorallocate ($im255255255);
$text_color imagecolorallocate ($im0,0,0);
imagestring ($im255,  "IMAGE ERROR"$text_color);
imagepng ($im);
imagedestroy($im);
}
}

?>


Night09

It can be done standalone without the news section. I had it on a guild site and it was pretty easy to implement. That would save butchering the news maybe?

Heres a similar example of how it was done http://www.pontikis.net/tip/?id=25 

Antechinus

Yes I know it can be done standalone. ;) Implementing the script is easy. I'm just somewhat wary of free decade-old scripts from obscure corners of the web, and would like an opinion on the quality of its coding, and whether it is advisable to make something a lot better instead of using this one.

Night09

The simpler the better, less to fix if it goes wrong and it worked ok on 2.0.x for us. ;)

Antechinus

Hmm. That one looks simple alright. Could do with a few tweaks.

Ideally what I would want to do is have a custom textarea on the admin>theme settings page (which is easy to make) and allow the admin to enter a comma separated list of image names (banner1.jpg, banner2.jpg, etc) then have the PHP implode (or would that be explode?) that in index.template.php to create the array (no big deal) and then spit that out as inline style on the header anchor, so that the image gets loaded as a background image for better performance, with the surrounding anchor size being predefined in index.css (responsive, of course).

ETA: I just RTFM. I would want explode on the list of image names. :D Would probably also want to include a limit on the amount of exploding, just in case some nutter uploaded 574 images to the banners folder.

I'm gonna do a bit more reading.

margarett

Actually if you're providing the images yourself, you don't need such a fancy script...

You just really need to establish a base folder, append it the image name (which you do by randomizing the array key, most likely), do a file_exist to check the image is there (probably repeat if not?) and, if so, spit out a common "img".
That script needs more stuff because it is making an image callable through a PHP file: to use that script you would use <img src="http://www.yabadaba.com/script.php">, but in your case you can just spit the image itself <img src="http://www.yabadaba.com/image_a.png">

Of course this exposes the image's filename (and path) but, if that's not a problem, then I would say it's far more easy to do...
Se forem conduzir, não bebam. Se forem beber... CHAMEM-ME!!!! :D

QuoteOver 90% of all computer problems can be traced back to the interface between the keyboard and the chair

Antechinus

TBH I can't see that exposing the path is any big deal, since "View page source" will do that for any inline image anyway, and "Inspect element" will do it for CSS background images.

Night09

As long as theres an index.php in the folder its just like any other then.

Antechinus

Quote from: margarett on January 14, 2015, 03:36:27 PMActually if you're providing the images yourself...

Well I'd provide at least one initially, but let people have the option of adding their own, or deleting the default from the list. It'd still require FTP or cPanel or similar to get the images into the folder, but anyone who can't handle that won't be running a forum for long.

margarett

Quote from: Antechinus on January 14, 2015, 03:48:53 PM
TBH I can't see that exposing the path is any big deal, since "View page source" will do that for any inline image anyway, and "Inspect element" will do it for CSS background images.
Not really. On a regular SMF instance where you upload your avatar (not here as it was modified) you can't see its full path, because it's called through a php script (see attached)
So you need to really consider all angles ;)

Quote from: Antechinus on January 14, 2015, 03:59:13 PM
It'd still require FTP or cPanel or similar to get the images into the folder, but anyone who can't handle that won't be running a forum for long.
:P True
Se forem conduzir, não bebam. Se forem beber... CHAMEM-ME!!!! :D

QuoteOver 90% of all computer problems can be traced back to the interface between the keyboard and the chair

Antechinus

Quote from: margarett on January 14, 2015, 04:05:50 PM
Quote from: Antechinus on January 14, 2015, 03:48:53 PM
TBH I can't see that exposing the path is any big deal, since "View page source" will do that for any inline image anyway, and "Inspect element" will do it for CSS background images.
Not really. On a regular SMF instance where you upload your avatar (not here as it was modified) you can't see its full path, because it's called through a php script (see attached)
So you need to really consider all angles ;)

Good point. So is exposing the path likely to present any problems in the case of banners?

Night09

QuoteGood point. So is exposing the path likely to present any problems in the case of banners?

Its unlikely as most sites you can view the background or banner anyway including here.

Illori

if you have the exact link visible, the images can be cached.

i had posted this in one of the charter boards.

Quote from: Illori
put this code in a file named rotator.php in your Sources folder

<?php

function getRandomFromArray($ar) {

    
mt_srand( (double)microtime() * 1000000 );

    
$num array_rand($ar);

    return 
$ar[$num];

}

 

function 
getImagesFromDir($path) {

    
$images = array();

    if ( 
$img_dir = @opendir($path) ) {

        while ( 
false !== ($img_file readdir($img_dir)) ) {

            
// checks for gif, jpg, png

            
if ( preg_match("/(\.gif|\.jpg|\.png)$/"$img_file) ) {

                
$images[] = $img_file;

            }

        }

        
closedir($img_dir);

    }

    return 
$images;

}

 

$root '';

// If images not in sub directory of current directory specify root 

//$root = $_SERVER['DOCUMENT_ROOT'];

 

global $settings$context;
$path $settings['default_theme_dir'] .  '/rotator/';
 
// Obtain list of images from directory 
$imgList = array();
if ( 
$img_dir = @opendir($path) )
{
while ( false !== ($img_file readdir($img_dir)) )
// checks for gif, jpg, png
if ( preg_match("/(\.gif|\.jpg|\.png)$/"$img_file) )
$imgList[] = $img_file;

closedir($img_dir);

$num array_rand($imgList);
$context['img_logo'] = $settings['theme_url'] .  '/rotator/' $imgList[$num];
}
else
{
$context['img_logo'] = $context['header_logo_url_html_safe'];


?>


put the images in a folder named rotator in your your default themes folder

from the default theme find
function template_body_above()
{
global $context, $settings, $options, $scripturl, $txt, $modSettings;

add after
require_once($sourcedir.'/rotator.php');

in this case we were replacing the logo so
<a href="', $scripturl, '">', empty($context['header_logo_url_html_safe']) ? $context['forum_name'] : '<img src="' . $context['header_logo_url_html_safe'] . '" alt="' . $context['forum_name'] . '" />', '</a>
is replaced with

<a href="', $scripturl, '">', empty($context['header_logo_url_html_safe']) ? $context['forum_name'] : '<img src="' . $context['img_logo'] . '" alt="' . $context['forum_name'] . '" />', '</a>

some of the above code came from members of the dev/customization teams

you would just need to edit it to fit where you want the image to show up in your theme

Antechinus

Ok, that would need some simple changing of paths for what I want, but that's a no-brainer. One question: what does the "mt_srand( (double)microtime() * 1000000 );" code do? Is that for rotating on a set time interval?

Arantor

Well, the rest of the code is about getting a random number, but the random number generator sometimes needs... priming to actually be basically random. That's what that code does.


Antechinus

Oh yeah, so I'm assuming that wouldn't require any admin input for image names, and would just grab whatever was in the banners folder. If correct, that's probably going to be better for the average mug.

Night09

Yeah should need no admin help as its set to grab images from the folder so all they need to do is upload them there.

Antechinus

That sounds like the way to go. I can just have a help blurb in admin telling them what to do, and a checkbox to enable rotation. Easy.

Night09

The only advice I would give is an image size range to suit so it doesnt kill the template if someone uploads a massive HD image or something daft like that.

Antechinus

I've already included an admin help section about that. Short version: use something around 1400x200 in medium quality jpg. :)

Antechinus

Hey I had an idea about this. If you were wanting to set this up as part of a custom theme, with theme-specific banners, and without using anything in Sources, it should be possible to do it more or less like this:

1/ Set up an images/banners folder, with at least one default banner inside it.
2/ Name all banners as banner_1.jpg, banner_2.jpg, etc.
3/ Append a basic PHP snippet to to pick a banner out of what's available. In essence:

<img id="forum_banner" style="max-width: ',!empty($settings['header_logo_width']) && $settings['header_logo_width'] < 100 ? $settings['header_logo_width']. '%;"' : '100%;"', ' src="', $settings['images_url'], '/banners/banner_', (rand ( int 1 , int 5 ) : int), '.jpg" alt="', $context['forum_name'], '" />


Where you'd also add a bit to pick up the maximum number of banners from an admin input. IOW, if you want to have 10 banners you'd stick 10 in a text input, and your PHP snippet in the template would pick that up for int $max. This should allow having a banner rotator entirely within the theme, with very little code.

Now tell me what I've missed. :D

Antechinus

#22
Just as a quick test, this seems to work:

echo '
<h1 id="forum_title" class="image_banner">
<a href="', $scripturl, '">
<img id="forum_banner" style="max-width: ',!empty($settings['header_logo_width']) && $settings['header_logo_width'] < 100 ? $settings['header_logo_width']. '%;"' : '100%;"';

$woof = $settings['number_recent_posts'];
$banner = rand(1, $woof);
echo '
src="', $settings['images_url'], '/', $context['theme_variant_url'], '/banners/banner_', $banner, '.jpg" alt="', $context['forum_name'], '" />
</a>
</h1>';


Obviously this is just hijacking an existing setting for quick trial run. Would need a custom setting in practice. Still, it works. With 13 banners in the images/banners folder, and recent posts on the board index set to 8, any page refresh or change cycles through the first 8 banners in the folder. No errors in the log either. Beats me why I didn't think of this before.  :)

ETA: Added in ', $context['theme_variant_url'], '/ for extra shiny.

drewactual

fwiw- i run a simple php script for this, as well as set it up to show on some pages and not on others.... the 'banner' image changes on each reload- or- it doesn't show at all... 


<?php
        
if( isset($_REQUEST['board'])) {
            echo
' <style> #upper_section{display:none;}#top-block-with{display:none;}</style>'; }
        elseif(isset(
$_REQUEST['topic'])) {
            echo
' <style> #upper_section{display:none;}#top-block-with{display:none;}</style>'; }
        elseif(isset(
$_REQUEST['action'])) {
            echo
' <style> #upper_section{display:none;}#top-block-with{display:none;}</style>'; }
        else {
            echo
' <style> #top-block-with{background:url(/images/background-top/';$random=rand(1,13);echo$random;echo'.jpg)no-repeat fixed;background-size:cover;position:relative;display:block;height:400px;width:100%;margin:0;}</style>'; }
?>



you can either have that code called from an external file using 'include', or, you can plop it right in your index.template... realize the code above is doing two things:

  • it's distinguishing between pages and either showing this banner, or not
  • it's randomizing (on reload) the banner image.

JUST TALKING ABOUT THE ROTATING IMAGE PART OF THE ABOVE CODE
the trick is using numbers as names... 1.jpg, 2.jpg, 3.jpg, ect... let's suppose you have 150 images to choose from- the code would be:
echo' <style> #top-block-with{background:url(/images/background-top/';$random=rand(1,150);echo$random;echo'.jpg)no-repeat fixed;background-size:cover;position:relative;display:block;height:400px;width:100%;margin:0;}</style>'; }

like i said, i tucked this away into a background image, and it's sizable and not something i want on every page...

you can see this live on https://www.cfb51.com or https://www.carolina-woodworkers.com ....

as you can see the code is simple, and... using the isset you can do a lot more with it.. I also control Open Graph and Twitter cards with it... offer board specific theme changes with it (same theme, really, different images to distinguish which by just a glance).

of all the ways to do this, i've found this the easiest and cleanest... now a true rotating banner?  i had one... it was a resource pig, using JS, so... i dropped it.

Antechinus

Yes that's quite neat too, although personally I'd be inclined to put more of the styling in a CSS file and use a class or id to call it.

I already have body class assigned by board, action, area, etc so I can easily bring those into play in the CSS too. I even have theme variant and language direction callable by the CSS. I like extra styling options. :)

And agree about resource pigs. Even a random banner on page load will be a bit of a pig until all the banners are cached by the browser.

Sir Osis of Liver

Seem to remember doing something like this once in Bloc's Enterprise theme.  IIRC, it had a button to select an image in upper right header, and I randomized it.

Ok, found it.  It was in 1.1 version, but you'll get the idea -



// Choose random topr pic
$pic = rand(1,5);

echo '

<div id="linktree">' , theme_linktree2() , '</div>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td><img src="',$settings['images_url'],'/img/topl.jpg" alt="" /></td>
<td width="99%" style="background: url(',$settings['images_url'],'/img/topm.jpg) repeat-x;">&nbsp;</td>
<td><img src="',$settings['images_url'],'/img/topr', $pic ,'.jpg" alt="" /></td>

</tr>
</table>



It werked gud!
Ashes and diamonds, foe and friend,
 we were all equal in the end.

                                     - R. Waters

Antechinus

Yep, I remember that image/button thing on Enterprise.* It was awesome cool at the time. :)

*That was back in the days when Bloc's themes used to drive me nuts because I didn't know any PHP.

Kindred

I used the enterprise script and then ported it in studio003 ...   it allows a full theme color choice  between 5 color sets based on css file selected by color name

Updating that for 2.1 now...
Слaва
Украинi

Please do not PM, IM or Email me with support questions.  You will get better and faster responses in the support boards.  Thank you.

"Loki is not evil, although he is certainly not a force for good. Loki is... complicated."

Antechinus

Umm, yes, the theme variant system has been part of SMF since the Neolithic. Not entirely sure what you are saying here.

Kindred

No, I didn't use the theme variants....

I reused the banner script for the enterprise theme, with a drop-down menu to change the css for the theme
Слaва
Украинi

Please do not PM, IM or Email me with support questions.  You will get better and faster responses in the support boards.  Thank you.

"Loki is not evil, although he is certainly not a force for good. Loki is... complicated."

Sir Osis of Liver

There's a 2.0 Enterprise, doesn't come up on theme site, did a couple of customizations with it (don't remember where).  Be nice if someone (i.e., Bloc) could make it responsive and/or port to 2.1.
Ashes and diamonds, foe and friend,
 we were all equal in the end.

                                     - R. Waters

Antechinus

@KIndred: Hey! You could combine that with the subject of this thread and have the CSS randomly changing on every page load for extra giggles. :D

ETA: Damn. Now I want to do evil thingz again.

Kindred

Слaва
Украинi

Please do not PM, IM or Email me with support questions.  You will get better and faster responses in the support boards.  Thank you.

"Loki is not evil, although he is certainly not a force for good. Loki is... complicated."

Advertisement: