├── .gitignore
├── template.php
├── README.md
└── index.php
/.gitignore:
--------------------------------------------------------------------------------
1 | *.[jJ][pP][gG]
2 | *.[jJ][pP][eE][gG]
3 | *.[pP][nN][gG]
4 | *.[gG][iI][fF]
5 |
--------------------------------------------------------------------------------
/template.php:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 | A gallery of pictures
30 |
31 |
32 | Picture /
33 |
34 |
85 |
86 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
[ Index ]
97 |
[ First ]
98 |
[ Previous ]
99 |
[ Next ]
100 |
[ Last ]
101 |
102 |
106 |
107 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Mini Gallery
2 |
3 | With this PHP script you'll get a full featured gallery in an instant. It does not take much more than copying two php files and your images to your web server.
4 |
5 | ## DISCONTINUED
6 |
7 | This project is quite old. It was originally written in PHP 3 and HTML 3.2, and has never really evolved since then. I stopped using PHP many years ago, so I cannot easily test changes to this project any more.
8 |
9 | For this reason, I won't maintain this project any longer. Feel free to fork and enhance it!
10 |
11 | ## Features
12 |
13 | Some features of this gallery script are:
14 |
15 | * Easy installation
16 | * Index page generation of all pictures
17 | * Automatic thumbnail generation
18 | * Individual captions for each picture
19 | * Multi language support
20 | * Layout is easily changed, even without PHP skills
21 | * Runs on almost any host who supports PHP
22 | * No database required
23 | * Source code available at [GitHub](https://github.com/shred/phpminigallery)
24 |
25 | ## Prerequisites
26 |
27 | This script is quite easy-going. PHP 4.1 is already sufficient, which is provided by almost all web hosts. Register globals may be enabled or disabled. The script is PHP 5 compliant.
28 |
29 | For thumbnail generation, either GD2, ImageMagick or GD is required. GD is not recommended though, and should only be used as a last resort, because the quality of the thumbnail images will be really poor. If you use ImageMagick, make sure PHP SafeMode is turned off.
30 |
31 | This script is entirely file-based, and does not involve any database programming.
32 |
33 | ## Usage
34 |
35 | PHP Mini Gallery is very simple to use. You won't need to have any PHP skills.
36 |
37 | First, you have to create a directory for the gallery. Make sure that the script is allowed to create files in this directory.
38 |
39 | Now you upload all your pictures into this directory. The only image formats allowed are JPEG, PNG and GIF. The file names need to have a correct suffix, and must not start with `th_`, because it is reserved for the thumbnail files. The PHP Mini Gallery shows the pictures in alphabetical order of their file names. I got myself used to name the pictures `01.jpg`, `02.jpg` and so on, but this is not required.
40 |
41 | If you want to add a caption to a picture (e.g. a description of the picture's content), you can place the text in another file, which is named like the picture this caption will belong to, but has an additional `.txt` suffix attached. Example: the caption file for the picture `04.jpg` would be named `04.jpg.txt`.
42 |
43 | Finally you have to place the PHP files `index.php` and `template.php` from the PHP Mini Gallery archive into that directory. And that's all!
44 |
45 | If you invoke the page with your browser, you'll first see an index print of all pictures' thumbnails. At the first invocation, the thumbnails will be created automatically, and will be stored in files with an appropriate file name, but `th_` attached before, and `.jpg` behind the file name. Example: the thumbnail of picture `04.jpg` is named `th_04.jpg.jpg`. The double jpg suffix is intentional. This first invocation could take a while until all thumbnails are created, and may even time out. For subsequent calls, the thumbnail files will be used though, so you will receive the index page much faster. PHP Mini Gallery will detect if you have modified a picture, and will automatically re-create its thumbnail image.
46 |
47 | If you click on a thumbnail, you will get the full size picture. Starting from there, you can see the next picture by clicking into the current picture, or you can go forward and back using the navigation links.
48 |
49 | ## Configuration
50 |
51 | At the beginning of the script `index.php`, you will find a few configuration parameters. PHP Mini Gallery already has reasonable default values, so you usually won't need to change them unless you really want to change them.
52 |
53 | ```php
54 | $CONFIG['thumb.width'] = 100; // Thumbnail width (pixels)
55 | $CONFIG['thumb.height'] = 100; // Thumbnail height (pixels)
56 | ```
57 |
58 | This is the maximum dimension of thumbnail pictures. While scaling, PHP Mini Gallery will take care to keep the aspect ratio of the picture.
59 |
60 | ```php
61 | $CONFIG['thumb.scale'] = 'gd2'; // Set to 'gd2', 'im' or 'gd'
62 | $CONFIG['tool.imagick'] = '/usr/X11R6/bin/convert'; // Path to convert
63 | ```
64 |
65 | Here you will set the scaling tool.
66 |
67 | * `gd2` selects the GD2 library, which is installed in most of the recent PHP setups. It will result a good quality without any installation hassles, and thus is the recommended setting.
68 | * `im` uses ImageMagick for scaling. You have to set the path to the `convert` tool in `tool.imagick`! Use this if GD2 is not available.
69 | * `gd` uses the legacy GD library, which should be available in almost all PHP installations. The quality is quite poor, though, so you should only take this one if you have no other choice.
70 |
71 | Note: You must set the absolute path to ImageMagick's `convert` tool. If you are in the unlucky situation to be confronted with a Windows server, also remember to double the backslashes (e.g. '`C:\\path\\to\\convert.exe`').
72 |
73 | ```php
74 | $CONFIG['index.cols'] = 6; // Colums per row on index print
75 | ```
76 |
77 | The number of picture colums at each row of the index print.
78 |
79 | ```php
80 | $CONFIG['template'] = 'template.php'; // Template file
81 | ```
82 |
83 | Path to the template file, which is used for HTML generation. If you want to use a common template file for several galleries, you can also set the path to this file here. The gallery will then only require the `index.php` file in each directory.
84 |
85 | ## Simple Layout Adaptions
86 |
87 | The PHP Mini Gallery is designed that all layout changes need to be made in the `template.php` file only. There are some special "tags" which can be used for this purpose, so you can adapt the gallery to your needs, without any PHP knowledge.
88 |
89 | These tags are available:
90 |
91 | * `...` - The content of this container will only be sent to the browser if the index print page is to be shown.
92 | * `...` - The content of this container will only be sent to the browser if a complete picture is to be shown. You cannot nest both tags, but you can use them as often as you want.
93 | * `...` - A link to the gallery's first picture. You can use it like an <a> tag. If there is no appropriate picture, the tag and its content will be omitted. Example: `[ First ]`
94 | * `...` - A link to the gallery's last image.
95 | * `...` - A link to the index print page.
96 | * `...` - A link to the previous picture.
97 | * `...` - A link to the next picture.
98 | * `` - This tag replaces the entire image tag and a link to the next picture. The CSS class `picimg` can be used to change the rendering of this picture. For index print view, this tag is empty.
99 | * `` - If there is a caption for this picture, its content will be inserted here. Otherwise the tag is empty.
100 | * `` - This tag replaces the entire table containing the thumbnails of all pictures. The CSS class `tabindex` can be used to change the rendering of the table. The CSS class thumbimg changes the rendering of the single thumbnail images.
101 | * `` - Will be replaced by the total count of the pictures.
102 | * `` - Will be replaced by the number of the current picture. This tag is empty for index print views.
103 |
104 | The tag parser isn't very smart, and can be fooled quite easily. You should take care to use the tags as explained here, otherwise they might not be recognized and replaced properly. You may want to use the packaged `template.php` as an example.
105 |
106 | ## Complex Layout Adaptions
107 |
108 | The `template.php` is included as PHP script, and thus can also contain PHP language parts. In especially complex cases, you can even implement the entire HTML creation here, instead of using the special tags. You will find all necessary information in the global `$CONTEXT` array.
109 |
110 | The `$CONTEXT` array contains these keys:
111 |
112 | * `'page'` - For complete picture view, you'll find 'picture' here, and 'index' for the index print view.
113 | * `'files'` - An array containing the file names of all pictures, in their output order. Thumbnails and scripts are not included here.
114 | * `'count'` - The number of pictures
115 | * `'current'` - For complete picture view, you'll find the number of the current picture, counted starting with 1. So the file name of the current picture you'll find in 'files' at `$CONTEXT['current']-1`.
116 | * `'first'` - File name of the first picture.
117 | * `'last'` - File name of the last picture.
118 | * `'prev'` - For complete picture view: file name of the previous picture. This entry is empty if the current picture is the first picture.
119 | * `'next'` - For complete picture view: file name of the next picture. This entry is empty if the current picture is the last picture.
120 | * `'pictag'` - For complete picture view: the entire image tag for the picture, and a link to the next picture.
121 | * `'caption'` - For complete picture view: if the current picture has a caption file, you'll find its content in here.
122 | * `'indextag'` - The entire thumbnail table with links to the appropriate pictures.
123 |
124 | The special tags will be replaced after executing the `template.php`, so you can randomly mix PHP script parts and special tags. The access to the `$CONTEXT` array is read only, though!
125 |
126 | ## License
127 |
128 | The PHP Mini Gallery is distributed under GPL ([Gnu Public License](http://www.gnu.org/licenses/gpl.html)). It is free of charge, even for commercial purposes.
129 |
130 | This software is open source. You man modify the source codes, as long as you also publish your changes under GPL. There is one exception: you do not need to publish a modified `template.php` file if it has only been customized to meet your web site's design.
131 |
132 | Keep in mind that you are only allowed to put pictures on the PHP Mini Gallery with the consent of the respective copyright owner.
133 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | filemtime($thfile))) {
44 | //--- Get information about the image ---
45 | $aySize = getimagesize($file);
46 | if(!isset($aySize)) die("Picture $file not recognized...");
47 | //--- Compute the thumbnail size, keep aspect ratio ---
48 | $srcWidth = $aySize[0]; $srcHeight = $aySize[1];
49 | if($srcWidth==0 || $srcHeight==0) { // Avoid div by zero
50 | $thWidth = 0;
51 | $thHeight = 0;
52 | }else if($srcWidth > $srcHeight) { // Landscape
53 | $thWidth = $CONFIG['thumb.width'];
54 | $thHeight = round(($CONFIG['thumb.width'] * $srcHeight) / $srcWidth);
55 | }else { // Portrait
56 | $thWidth = round(($CONFIG['thumb.height'] * $srcWidth) / $srcHeight);
57 | $thHeight = $CONFIG['thumb.height'];
58 | }
59 | //--- Get scale mode ---
60 | $scmode = strtolower($CONFIG['thumb.scale']);
61 | //--- Create source image ---
62 | if($scmode!='im') {
63 | switch($aySize[2]) {
64 | case 1: $imgPic = imagecreatefromgif($file); break;
65 | case 2: $imgPic = imagecreatefromjpeg($file); break;
66 | case 3: $imgPic = imagecreatefrompng($file); break;
67 | default: die("Picture $file must be either JPEG, PNG or GIF...");
68 | }
69 | }
70 | //--- Scale it ---
71 | switch($scmode) {
72 | case 'gd2': // GD2
73 | $imgThumb = imagecreatetruecolor($thWidth, $thHeight);
74 | imagecopyresampled($imgThumb, $imgPic, 0,0, 0,0, $thWidth,$thHeight, $srcWidth,$srcHeight);
75 | break;
76 | case 'gd': // GD
77 | $imgThumb = imagecreate($thWidth,$thHeight);
78 | imagecopyresized($imgThumb, $imgPic, 0,0, 0,0, $thWidth,$thHeight, $srcWidth,$srcHeight);
79 | break;
80 | case 'im': // Image Magick
81 | exec(sprintf(
82 | '%s -geometry %dx%d -interlace plane %s jpeg:%s',
83 | $CONFIG['tool.imagick'],
84 | $CONFIG['thumb.width'],
85 | $CONFIG['thumb.height'],
86 | $file,
87 | $thfile
88 | ));
89 | break;
90 | default:
91 | die("Unknown scale mode ".$CONFIG['thumb.scale']);
92 | }
93 | //--- Save it ---
94 | if($scmode!='im') {
95 | imagejpeg($imgThumb, $thfile);
96 | imagedestroy($imgPic);
97 | imagedestroy($imgThumb);
98 | }
99 | }
100 |
101 | //--- Check if there is an if-modified-since header ---
102 | $fileModified = date('D, d M Y H:i:s \G\M\T', filemtime($thfile));
103 | if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $_SERVER['HTTP_IF_MODIFIED_SINCE']==$fileModified) {
104 | header('HTTP/1.0 304 Not Modified');
105 | exit();
106 | }
107 |
108 | //--- Send the thumbnail to the browser ---
109 | session_cache_limiter('');
110 | header('Content-Type: image/jpeg');
111 | header("Content-Length: ".filesize($thfile));
112 | header("Last-Modified: $fileModified");
113 | readfile($thfile);
114 | exit();
115 | }else {
116 | //--- Tell there is no image like that ---
117 | if(is_file($thfile)) unlink($thfile); // Delete a matching thumbnail file
118 | header('HTTP/1.0 404 Not Found');
119 | print('Sorry, this picture was not found');
120 | exit();
121 | }
122 | }
123 |
124 | /*=== CREATE CONTEXT ===*/
125 | $CONTEXT = array();
126 |
127 | /*=== GET FILE LISTING ===*/
128 | $ayFiles = array();
129 | $dh = opendir('.');
130 | while(($file = readdir($dh)) !== false) {
131 | if($file[0]=='.') continue; // No dirs and temp files
132 | if(substr($file,0,3) == 'th_') continue; // No thumbnails
133 | if(preg_match('#\.(jpe?g|png|gif)$#i', $file)) {
134 | if(is_file($file) && is_readable($file)) {
135 | $ayFiles[] = $file;
136 | }
137 | }
138 | }
139 | sort($ayFiles);
140 | $CONTEXT['count'] = count($ayFiles);
141 | $CONTEXT['files'] =& $ayFiles;
142 |
143 | /*=== SHOW A PICTURE? ===*/
144 | if(isset($_GET['pic'])) {
145 | $file = trim($_GET['pic']);
146 | //--- Protect against hacker attacks ---
147 | if(preg_match('#\.\.|/#', $file)) die("Illegal characters in path!");
148 | //--- Check existence ---
149 | if(!(is_file($file) && is_readable($file))) {
150 | header('HTTP/1.0 404 Not Found');
151 | print('Sorry, this picture was not found');
152 | exit();
153 | }
154 | $CONTEXT['page'] = 'picture';
155 | //--- Find our index ---
156 | $index = array_search($file, $ayFiles);
157 | if(!isset($index) || $index===false) die("Invalid picture $file");
158 | $CONTEXT['current'] = $index+1;
159 | //--- Get neighbour pictures ---
160 | $CONTEXT['first'] = $ayFiles[0];
161 | $CONTEXT['last'] = $ayFiles[count($ayFiles)-1];
162 | if($index>0)
163 | $CONTEXT['prev'] = $ayFiles[$index-1];
164 | if($index',
170 | htmlspecialchars($file),
171 | htmlspecialchars($pWidth),
172 | htmlspecialchars($pHeight),
173 | htmlspecialchars($index+1)
174 | );
175 | if(isset($CONTEXT['next'])) {
176 | $page = sprintf('%s', htmlspecialchars($CONTEXT['next']), $page);
177 | }
178 | $CONTEXT['pictag'] = $page;
179 | if(is_file($file.'.txt') && is_readable($file.'.txt')) {
180 | $CONTEXT['caption'] = join('', file($file.'.txt'));
181 | }
182 | }
183 |
184 | /*=== SHOW INDEX PRINT ===*/
185 | else{
186 | //--- Set context ---
187 | $CONTEXT['page'] = 'index';
188 | $CONTEXT['first'] = $ayFiles[0];
189 | $CONTEXT['last'] = $ayFiles[count($ayFiles)-1];
190 | }
191 |
192 | //--- Assemble the index table ---
193 | $page = ''."\n";
194 | $cnt = 0;
195 | foreach($ayFiles as $key=>$file) {
196 | if($cnt % $CONFIG['index.cols'] == 0) $page .= '';
197 | $page .= sprintf(
198 | ' | ',
199 | htmlspecialchars($file),
200 | htmlspecialchars($file),
201 | htmlspecialchars($key+1)
202 | );
203 | $cnt++;
204 | if($cnt % $CONFIG['index.cols'] == 0) $page .= '
'."\n";
205 | }
206 | //--- Fill empty cells in last row ---
207 | $close = false;
208 | while($cnt % $CONFIG['index.cols'] != 0) {
209 | $page .= ' | ';
210 | $close = true;
211 | $cnt++;
212 | }
213 | if($close) $page .= ''."\n";
214 | $page .= '
';
215 | //--- Set content ---
216 | $CONTEXT['indextag'] = $page;
217 |
218 | /*=== GET TEMPLATE CONTENT ===*/
219 | ob_start();
220 | require($CONFIG['template']);
221 | $template = ob_get_contents();
222 | ob_end_clean();
223 |
224 | /*=== REMOVE UNMATCHING SECTION ===*/
225 | if($CONTEXT['page']=='index') {
226 | $template = preg_replace('#.*?#s', '', $template);
227 | $template = preg_replace('#(.*?)#s', '$1', $template);
228 | }else {
229 | $template = preg_replace('#.*?#s', '', $template);
230 | $template = preg_replace('#(.*?)#s', '$1', $template);
231 | }
232 |
233 | /*=== REPLACE TEMPLATE TAGS ===*/
234 | //--- Always present neighbour links ---
235 | $aySearch = array(
236 | '', '',
237 | '', '',
238 | '', ''
239 | );
240 | $ayReplace = array();
241 | $ayReplace[] = sprintf('', htmlspecialchars($CONTEXT['first']));
242 | $ayReplace[] = '';
243 | $ayReplace[] = sprintf('', htmlspecialchars($CONTEXT['last']));
244 | $ayReplace[] = '';
245 | $ayReplace[] = '';
246 | $ayReplace[] = '';
247 | $template = str_replace($aySearch, $ayReplace, $template);
248 |
249 | //--- Link to previous picture ---
250 | if(isset($CONTEXT['prev'])) {
251 | $aySearch = array('', '');
252 | $ayReplace = array(
253 | sprintf('', htmlspecialchars($CONTEXT['prev'])),
254 | ''
255 | );
256 | $template = str_replace($aySearch, $ayReplace, $template);
257 | }else {
258 | $template = preg_replace('#.*?#s', '', $template);
259 | }
260 |
261 | //--- Link to next picture ---
262 | if(isset($CONTEXT['next'])) {
263 | $aySearch = array('', '');
264 | $ayReplace = array(
265 | sprintf('', htmlspecialchars($CONTEXT['next'])),
266 | ''
267 | );
268 | $template = str_replace($aySearch, $ayReplace, $template);
269 | }else {
270 | $template = preg_replace('#.*?#s', '', $template);
271 | }
272 |
273 | //--- Image, Index Print, Caption ---
274 | $aySearch = array('', '', '', '', '');
275 | $ayReplace = array(
276 | (isset($CONTEXT['pictag']) ? $CONTEXT['pictag'] : ''),
277 | (isset($CONTEXT['indextag']) ? $CONTEXT['indextag'] : ''),
278 | (isset($CONTEXT['caption']) ? $CONTEXT['caption'] : ''),
279 | $CONTEXT['count'],
280 | (isset($CONTEXT['current']) ? $CONTEXT['current'] : ''),
281 | );
282 | $template = str_replace($aySearch, $ayReplace, $template);
283 |
284 | /*=== PRINT TEMPLATE ===*/
285 | ob_start('ob_gzhandler');
286 | print($template);
287 | print("\n".''."\n");
288 | exit();
289 | ?>
290 |
--------------------------------------------------------------------------------