]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/PhotoAlbum.php
Cleanup of CONSTANT pollution.
[SourceForge/phpwiki.git] / lib / plugin / PhotoAlbum.php
1 <?php // -*-php-*-
2 rcs_id('$Id: PhotoAlbum.php,v 1.10 2004-12-01 19:34:13 rurban Exp $');
3 /*
4  Copyright 2003, 2004 $ThePhpWikiProgrammingTeam
5  
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /**
24  * Display an album of a set of photos with optional descriptions.
25  *
26  * @author: Ted Vinke <teddy@jouwfeestje.com>
27  *          Reini Urban (local fs)
28  *
29  * Usage:
30  * <?plugin PhotoAlbum
31  *          src="http://server/textfile" or localfile or localdir or nothing
32  *          mode=[column|row]
33  *          desc=true
34  *          sort=false
35  *          height=50%
36  *          width=50%
37  *
38  * "src": textfile of images or directory of images (local or remote)
39  *      Local or remote e.g. http://myserver/images/MyPhotos.txt or http://myserver/images/
40  *      Possible content of a valid textfile:
41  *      photo-01.jpg; Me and my girlfriend
42  *      photo-02.jpg
43  *      christmas.gif; Merry Christmas!
44
45  *     Inside textfile, filenames and optional descriptions are seperated by
46  *     semi-colon on each line. Listed files must be in same directory as textfile 
47  *     itself, so don't use relative paths inside textfile.
48  *
49  * "url": defines the the webpath to the srcdir directory (formerly called weblocation)
50  */
51
52 /**
53  * TODO:
54  * - implement WinXP style 'slide' mode, javascript tricks
55  * - specify picture(s) as parameter(s)
56  * - limit amount of pictures on one page
57  * - use PHP to really resize or greyscale images (only where GD library supports it)
58  *
59  * KNOWN ISSUES:
60  * - reading height and width from images with spaces in their names fails.
61  *
62  * Fixed album location idea by Philip J. Hollenback. Thanks!
63  */
64
65 class WikiPlugin_PhotoAlbum
66 extends WikiPlugin
67 {
68     function getName () {
69         return _("PhotoAlbum");
70     }
71
72     function getDescription () {
73         return _("Displays a set of photos listed in a text file with optional descriptions");
74     }
75
76     function getVersion() {
77         return preg_replace("/[Revision: $]/", '',
78                             "\$Revision: 1.10 $");
79     }
80
81 // Avoid nameclash, so it's disabled. We allow any url.
82 // define('allow_album_location', true);
83 // define('album_location', 'http://kw.jouwfeestje.com/foto/redactie');
84 // define('album_default_extension', '.jpg');
85 // define('desc_separator', ';');
86
87     function getDefaultArguments() {
88         return array('src'      => '',          // textfile of image list, or local dir.
89                      'url'      => '',          // if src=localfs, url prefix (webroot for the links)
90                      'mode'     => 'normal',    // normal|thumbs|tiles|list
91                         // "normal" - Normal table which shows photos full-size
92                         // "thumbs" - WinXP thumbnail style
93                         // "tiles"  - WinXP tiles style
94                         // "list"   - WinXP list style
95                         // "slide"  - Not yet implemented
96                      'numcols'  => 3,           // photos per row, columns
97                      'showdesc' => 'both',      // none|name|desc|both
98                         // "none"   - No descriptions next to photos
99                         // "name"   - Only filename shown
100                         // "desc"   - Only description (from textfile) shown
101                         // "both"        - If no description found, then filename will be used
102                      'link'     => true,        // show link to original sized photo
103                         // If true, each image will be hyperlinked to a page where the single 
104                         // photo will be shown full-size. Only works when mode != 'normal'
105                      'attrib'   => '',          // 'sort, nowrap, alt'
106                         // attrib arg allows multiple attributes: attrib=sort,nowrap,alt
107                         // 'sort' sorts alphabetically, 'nowrap' for cells, 'alt' to use
108                         // descs instead of filenames in image ALT-tags
109                      'bgcolor'  => '#eae8e8',   // cell bgcolor (lightgrey)
110                      'hlcolor'  => '#c0c0ff',   // highlight color (lightblue)
111                      'align'    => 'center',    // alignment of table
112                      'height'   => 'auto',      // image height (auto|75|100%)
113                      'width'    => 'auto',      // image width (auto|75|100%)
114                      // Size of shown photos. Either absolute value (e.g. "50") or
115                      // HTML style percentage (e.g. "75%") or "auto" for no special
116                      // action.
117                      'cellwidth'=> 'image',     // cell (auto|equal|image|75|100%)
118                      // Width of cells in table. Either absolute value in pixels, HTML
119                      // style percentage, "auto" (no special action), "equal" (where
120                      // all columns are equally sized) or "image" (take height and
121                      // width of the photo in that cell).
122                      'tablewidth'=> false,      // table (75|100%)
123                      'p'        => false,       // "displaythissinglephoto.jpg"
124                      'h'        => false,       // "highlightcolorofthisphoto.jpg"
125                      );
126     }
127     // descriptions (instead of filenames) for image alt-tags
128
129     function run($dbi, $argstr, &$request, $basepage) {
130         extract($this->getArgs($argstr, $request));
131
132         $attributes = $attrib ? explode(",", $attrib) : array();
133         $photos = array();
134         $html = HTML();
135
136         // check all parameters
137         // what type do we have?
138         if (!$src) {
139             $showdesc  = 'none';
140             $src   = $request->getArg('pagename');
141             $error = $this->fromLocation($src, $photos);
142         } else {
143             $error = $this->fromFile($src, $photos, $url);
144         }
145         if ($error) {
146             return $this->error($error);
147         }
148
149         if ($numcols < 1) $numcols = 1;
150         if ($align != 'left' && $align != 'center' && $align != 'right') {
151             $align = 'center';
152         }
153         if (count($photos) == 0) return;
154
155         if (in_array("sort", $attributes))
156             sort($photos);
157
158         if ($p) {
159             $mode = "normal";
160         }
161
162         // set some fixed properties for each $mode
163         if ($mode == 'thumbs' || $mode == 'tiles') {
164             $attributes = array_merge($attributes, "alt");
165             $attributes = array_merge($attributes, "nowrap");
166             $cellwidth  = 'auto'; // else cell won't nowrap
167             $showdesc   = 'name';
168             $width      = 50;
169         } elseif ($mode == 'list') {
170             $numcols    = 1;
171             $cellwidth  = "auto";
172             if ($showdesc != "none") {
173                 $showdesc = "desc";
174             }
175         }
176
177         $row = HTML();
178         while (list($key, $value) = each($photos))  {
179             if ($p && basename($value["name"]) != "$p") {
180                 continue;
181             }
182             if ($h && basename($value["name"]) == "$h") {
183                 $color = $hlcolor ? $hlcolor : $bgcolor;
184             } else {
185                 $color = $bgcolor;
186             }
187             // $params will be used for each <img > tag
188             $params = array('src'    => $value["name"],
189                             'border' => "0",
190                             'alt'    => ($value["desc"] != "" and in_array("alt", $attributes))
191                                         ? $value["desc"]
192                                         : basename($value["name"]));
193             // check description
194             switch ($showdesc) {
195                 case 'none':
196                     $value["desc"] = '';
197                     break;
198                 case 'name':
199                     $value["desc"] = basename($value["name"]);
200                     break;
201                 case 'desc':
202                     break;
203                 default: // 'both'
204                     if (!$value["desc"]) $value["desc"] = basename($value["name"]);
205                     break;
206             }
207
208             // FIXME: get getimagesize to work with names with spaces in it.
209             // convert $value["name"] from webpath to local path
210             $size = @getimagesize($value["name"]); // try " " => "\\ "
211             if (!$size and !empty($value["src"])) {
212                 $size = @getimagesize($value["src"]);
213                 if (!$size) {
214                     trigger_error("Unable to getimagesize(".$value["name"].")", 
215                                   E_USER_NOTICE);
216                 }
217             }
218
219             $newwidth = $this->newSize($size[0], $width);
220             $newheight = $this->newSize($size[1], $height);
221
222             if ($width != 'auto' && $newwidth > 0) {
223                 $params = array_merge($params, array("width" => $newwidth));
224             }
225             if ($height != 'auto' && $newheight > 0) {
226                 $params = array_merge($params, array("height" => $newheight));
227             }
228
229             // cell operations
230             $cell = array('align'   => "center",
231                           'valign'  => "top",
232                           'bgcolor' => "$color");
233             if ($cellwidth != 'auto') {
234                 if ($cellwidth == 'equal') {
235                     $newcellwidth = round(100/$numcols)."%";
236                 } else if ($cellwidth == 'image') {
237                     $newcellwidth = $newwidth;
238                 } else {
239                     $newcellwidth = $cellwidth;
240                 }
241                 $cell = array_merge($cell, array("width" => $newcellwidth));
242             }
243             if (in_array("nowrap", $attributes)) {
244                 $cell = array_merge($cell, array("nowrap" => "nowrap"));
245             }
246             //create url to display single larger version of image on page
247             $url        = WikiURL($request->getPage(),
248                           array("p" => basename($value["name"])));
249             $b_url      = WikiURL($request->getPage(),
250                           array("h" => basename($value["name"]))).
251                                                 "#".
252                                                 basename($value["name"]);
253             $url_text   = $link ? HTML::a(array("href" => "$url"),
254                                                 basename($value["name"])) :
255                                                 basename($value["name"]);
256             if (! $p) {
257                 $url_image = $link ? HTML::a(array("href" => "$url"),
258                                                    HTML::img($params)) :
259                                                    HTML::img($params);
260             } else {
261                 $url_image = $link ? HTML::a(array("href" => "$b_url"),
262                                                    HTML::img($params)) :
263                                                    HTML::img($params);
264             }
265             $url_text = HTML::a(array("name" => basename($value["name"])),
266                                       $url_text);
267             // here we use different modes
268             if ($mode == 'tiles') {
269                 $row->pushContent(HTML::td($cell,
270                      HTML::table(array("cellpadding" => 1, "border" => 0),
271                      HTML::tr(
272                            HTML::td(array("valign" => "top", "rowspan" => 2),
273                                            $url_image),
274                            HTML::td(array("valign" => "top", "nowrap" => 0),
275                                           HTML::small(HTML::strong($url_text)),
276                                           HTML::br(),
277                                           HTML::small($size[0].
278                                                       " x ".
279                                                       $size[1].
280                                                       " pixels"))
281                               ))));
282             } elseif ($mode == 'list') {
283                 $desc = ($showdesc != 'none') ? $value["desc"] : '';
284                 $row->pushContent(
285                     HTML::td(array("valign"  => "top",
286                                    "nowrap"  => 0,
287                                    "bgcolor" => $color),
288                                    HTML::small(HTML::strong($url_text))));
289                 $row->pushContent(
290                     HTML::td(array("valign"  => "top",
291                                    "nowrap"  => 0,
292                                    "bgcolor" => $color),
293                                    HTML::small($size[0].
294                                                " x ".
295                                                $size[1].
296                                                " pixels")));
297
298                 if ($desc != '') {
299                     $row->pushContent(HTML::td(array("valign"  => "top",
300                                                      "nowrap"  => 0,
301                                                      "bgcolor" => $color),
302                                                      HTML::small($desc)));
303                 }
304             } elseif ($mode == 'thumbs') {
305                 $desc = ($showdesc != 'none') ?
306                         HTML::p(HTML::a(array("href" => "$url"),
307                                         $url_text)) :
308                                         '';
309                 $row->pushContent(
310                     (HTML::td($cell,
311                               $url_image,
312                               // FIXME: no HtmlElement for fontsizes?
313                               // rurban: use ->setAttr("style","font-size:small;")
314                               //         but better use a css class
315                               HTML::span(array('class'=>'gensmall'),$desc)
316                               )));
317             } elseif ($mode == 'normal') {
318                 $desc = ($showdesc != 'none') ? HTML::p($value["desc"]) : '';
319                 $row->pushContent(
320                     (HTML::td($cell,
321                               $url_image,
322                               // FIXME: no HtmlElement for fontsizes?
323                               HTML::span(array('class'=>'gensmall'),$desc)
324                               )));
325             //} elseif ($mode == 'slide') {
326             //}
327             } else {
328                 return $this->error(fmt("Invalid argument: %s=%s", 'mode', $mode));
329             }
330
331             // no more images in one row as defined by $numcols
332             if ( ($key + 1) % $numcols == 0 ||
333                  ($key + 1) == count($photos) ||
334                   $p) {
335                 $html->pushcontent(HTML::tr($row));
336                 $row->setContent('');
337             }
338         }
339
340         //create main table
341         $html = HTML::table(array("border"      => 0,
342                                   "cellpadding" => 5,
343                                   "cellspacing" => 2,
344                                   "width"       => $tablewidth),
345                                   $html);
346         // align all
347         return HTML::div(array("align" => $align), $html);
348     }
349
350     /**
351      * Calculate the new size in pixels when the original size
352      * with a value is given.
353      *
354      * @param integer $oldSize Absolute no. of pixels
355      * @param mixed $value Either absolute no. or HTML percentage e.g. '50%'
356      * @return integer New size in pixels
357      */
358     function newSize($oldSize, $value) {
359         if (trim(substr($value,strlen($value)-1)) != "%") {
360             return $value;
361         }
362         $value = str_replace("%", "", $value);
363         return round(($oldSize*$value)/100);
364     }
365
366     /**
367     * fromLocation - read only one picture from fixed album_location
368     * and return it in array $photos
369     *
370     * @param string $src Name of page
371     * @param array $photos
372     * @return string Error if fixed location is not allowed
373     */
374     function fromLocation($src, &$photos) {
375         /*if (!allow_album_location) {
376             return $this->error(_("Fixed album location is not allowed. Please specify parameter src."));
377         }*/
378         //FIXME!
379         if (! IsSafeURL($src)) {
380             return $this->error(_("Bad url in src: remove all of <, >, \""));
381         }
382         $photos[] = array ("name" => $src, //album_location."/$src".album_default_extension,
383                            "desc" => "");
384     }
385
386     /**
387      * fromFile - read pictures & descriptions (separated by ;)
388      *            from $src and return it in array $photos
389      *
390      * @param string $src path to dir or textfile (local or remote)
391      * @param array $photos
392      * @return string Error when bad url or file couldn't be opened
393      */
394     function fromFile($src, &$photos, $webpath='') {
395         $src_bak = $src;
396         if (! IsSafeURL($src)) {
397             return $this->error(_("Bad url in src: remove all of <, >, \""));
398         }
399         if (preg_match('/^(http|ftp|https):\/\//i', $src)) {
400             $src = url_get_contents($src);
401         }
402         if (!file_exists($src) and file_exists(PHPWIKI_DIR . "/$src")) {
403             $src = PHPWIKI_DIR . "/$src";
404         }
405         // check if src is a directory
406         if (file_exists($src) and filetype($src) == 'dir') {
407             //all images
408             $list = array();
409             foreach (array('jpeg','jpg','png','gif') as $ext) {
410                 $fileset = new fileSet($src, "*.$ext");
411                 $list = array_merge($list, $fileset->getFiles());
412             }
413             // convert dirname($src) (local fs path) to web path
414             natcasesort($list);
415             if (! $webpath ) {
416                 // assume relative src. default: "themes/Hawaiian/images/pictures"
417                 $webpath = DATA_PATH . '/' . $src_bak;
418             }
419             foreach ($list as $file) {
420                 // convert local path to webpath
421                 $photos[] = array ("name" => $webpath . "/$file",
422                                    "src"  => $src . "/$file",
423                                    "desc" => "",
424                                    );
425             }
426             return;
427         }
428         @$fp = fopen ($src, "r");
429         if (!$fp) {
430             return $this->error(fmt("Unable to read src='%s'", $src));
431         }
432         while ($data = fgetcsv ($fp, 1024, ';')) {
433             if (count($data) == 0 || empty($data[0]))
434                 continue;
435             if (empty($data[1])) $data[1] = '';
436             $photos[] = array ("name" => dirname($src)."/".trim($data[0]),
437                                "desc" => trim($data[1]));
438         }
439         fclose ($fp);
440     }
441 };
442
443 // $Log: not supported by cvs2svn $
444 // Revision 1.9  2004/07/08 20:30:07  rurban
445 // plugin->run consistency: request as reference, added basepage.
446 // encountered strange bug in AllPages (and the test) which destroys ->_dbi
447 //
448 // Revision 1.8  2004/06/01 15:28:01  rurban
449 // AdminUser only ADMIN_USER not member of Administrators
450 // some RateIt improvements by dfrankow
451 // edit_toolbar buttons
452 //
453 // Revision 1.7  2004/05/03 20:44:55  rurban
454 // fixed gettext strings
455 // new SqlResult plugin
456 // _WikiTranslation: fixed init_locale
457 //
458 // Revision 1.6  2004/04/18 00:19:30  rurban
459 // better default example with local src, don't require weblocation for
460 // the default setup, better docs, fixed ini_get => get_cfg_var("allow_url_fopen"),
461 // no HttpClient lib yet.
462 //
463 // Revision 1.5  2004/03/09 12:10:23  rurban
464 // fixed getimagesize problem with local dir.
465 //
466 // Revision 1.4  2004/02/28 21:14:08  rurban
467 // generally more PHPDOC docs
468 //   see http://xarch.tu-graz.ac.at/home/rurban/phpwiki/xref/
469 // fxied WikiUserNew pref handling: empty theme not stored, save only
470 //   changed prefs, sql prefs improved, fixed password update,
471 //   removed REPLACE sql (dangerous)
472 // moved gettext init after the locale was guessed
473 // + some minor changes
474 //
475 // Revision 1.3  2004/02/27 08:03:35  rurban
476 // Update from version 1.2 by Ted Vinke
477 // implemented the localdir support
478 //
479 // Revision 1.2  2004/02/17 12:11:36  rurban
480 // added missing 4th basepage arg at plugin->run() to almost all plugins. This caused no harm so far, because it was silently dropped on normal usage. However on plugin internal ->run invocations it failed. (InterWikiSearch, IncludeSiteMap, ...)
481 //
482 // Revision 1.1  2003/01/05 04:21:06  carstenklapp
483 // New plugin by Ted Vinke (sf tracker patch #661189)
484 //
485
486 // For emacs users
487 // Local Variables:
488 // mode: php
489 // tab-width: 8
490 // c-basic-offset: 4
491 // c-hanging-comment-ender-p: nil
492 // indent-tabs-mode: nil
493 // End:
494 ?>