1<?php
2/**
3 * Functions used to display content in themes.
4 * @package functions
5 * @subpackage template-functions
6 */
7// force UTF-8 Ø
8
9require_once(dirname(__FILE__) . '/functions.php');
10if (!defined('SEO_FULLWEBPATH')) {
11	define('SEO_FULLWEBPATH', FULLWEBPATH);
12	define('SEO_WEBPATH', WEBPATH);
13}
14
15//******************************************************************************
16//*** Template Functions *******************************************************
17//******************************************************************************
18
19/* * * Generic Helper Functions ************ */
20/* * *************************************** */
21
22/**
23 * Returns the zenphoto version string
24 */
25function getVersion() {
26	return ZENPHOTO_VERSION;
27}
28
29/**
30 * Prints the zenphoto version string
31 */
32function printVersion() {
33	echo getVersion();
34}
35
36/**
37 * Print any Javascript required by zenphoto.
38 */
39function printZenJavascripts() {
40	global $_zp_current_album;
41	?>
42	<script type="text/javascript" src="<?php echo WEBPATH . "/" . ZENFOLDER; ?>/js/jquery.js"></script>
43	<?php
44	if(zp_loggedin()) {
45		?>
46		<script type="text/javascript" src="<?php echo WEBPATH . "/" . ZENFOLDER; ?>/js/zenphoto.js"></script>
47		<link rel="stylesheet" href="<?php echo WEBPATH . '/' . ZENFOLDER; ?>/admintoolbox.css" type="text/css" />
48		<?php
49	}
50}
51
52/**
53 * Prints the clickable drop down toolbox on any theme page with generic admin helpers
54 *
55 */
56function adminToolbox() {
57	global $_zp_current_album, $_zp_current_image, $_zp_current_search, $_zp_gallery_page, $_zp_gallery, $_zp_current_admin_obj, $_zp_loggedin, $_zp_conf_vars;
58	if (zp_loggedin()) {
59		$zf = FULLWEBPATH . "/" . ZENFOLDER;
60		$page = getCurrentPage();
61		ob_start();
62		?>
63		<script type="text/javascript">
64			// <!-- <![CDATA[
65			var deleteAlbum1 = "<?php echo gettext("Are you sure you want to delete this item?"); ?>";
66			var deleteAlbum2 = "<?php echo gettext("Are you Absolutely positively sure you want to delete this item? THIS CANNOT BE UNDONE!"); ?>";
67			function newAlbum(folder, albumtab) {
68				var album = prompt('<?php echo gettext('New album name?'); ?>', '<?php echo gettext('new album'); ?>');
69				if (album) {
70					launchScript('<?php echo $zf; ?>/admin-edit.php', ['action=newalbum', 'folder=' + encodeURIComponent(folder), 'name=' + encodeURIComponent(album), 'albumtab=' + albumtab, 'XSRFToken=<?php echo getXSRFToken('newalbum'); ?>']);
71				}
72			}
73			// ]]> -->
74		</script>
75		<div id="zp__admin_module">
76			<div id="zp__admin_info">
77				<span class="zp_logo">ZP</span>
78				<span class="zp_user"> <?php echo $_zp_current_admin_obj->getUser(); ?>
79					<?php
80					if(array_key_exists('site_upgrade_state', $_zp_conf_vars)) {
81						if($_zp_conf_vars['site_upgrade_state'] == 'closed_for_test') {
82							echo ' | <span class="zp_sitestatus">' . gettext('Test mode') . '</span>';
83						}
84					}
85					?>
86				</span>
87			</div>
88			<button type="button" id="zp__admin_link" onclick="javascript:toggle('zp__admin_data');">
89				<?php echo gettext('Admin'); ?>
90			</button>
91			<div id="zp__admin_data" style="display: none;">
92				<ul>
93				<?php
94				$outputA = ob_get_contents();
95				ob_end_clean();
96				ob_start();
97
98				if (zp_loggedin(OVERVIEW_RIGHTS)) {
99					?>
100					<li>
101						<?php printLinkHTML($zf . '/admin.php', gettext("Overview"), NULL, NULL, NULL); ?>
102					</li>
103					<?php
104				}
105				if (zp_loggedin(UPLOAD_RIGHTS | FILES_RIGHTS | THEMES_RIGHTS)) {
106					?>
107					<li>
108						<?php printLinkHTML($zf . '/admin-upload.php', gettext("Upload"), NULL, NULL, NULL); ?>
109					</li>
110					<?php
111				}
112				if (zp_loggedin(ALBUM_RIGHTS)) {
113					?>
114					<li>
115						<?php printLinkHTML($zf . '/admin-edit.php', gettext("Albums"), NULL, NULL, NULL); ?>
116					</li>
117					<?php
118				}
119				zp_apply_filter('admin_toolbox_global', $zf);
120
121				if (zp_loggedin(TAGS_RIGHTS)) {
122					?>
123					<li>
124						<?php printLinkHTML($zf . '/admin-tags.php', gettext("Tags"), NULL, NULL, NULL); ?>
125					</li>
126					<?php
127				}
128				if (zp_loggedin(USER_RIGHTS)) {
129					?>
130					<li>
131						<?php printLinkHTML($zf . '/admin-users.php', gettext("Users"), NULL, NULL, NULL); ?>
132					</li>
133					<?php
134				}
135				if (zp_loggedin(OPTIONS_RIGHTS)) {
136					?>
137					<li>
138						<?php printLinkHTML($zf . '/admin-options.php?tab=general', gettext("Options"), NULL, NULL, NULL); ?>
139					</li>
140					<?php
141				}
142				if (zp_loggedin(THEMES_RIGHTS)) {
143					?>
144					<li>
145						<?php printLinkHTML($zf . '/admin-themes.php', gettext("Themes"), NULL, NULL, NULL); ?>
146					</li>
147					<?php
148				}
149				if (zp_loggedin(ADMIN_RIGHTS)) {
150					?>
151					<li>
152						<?php printLinkHTML($zf . '/admin-plugins.php', gettext("Plugins"), NULL, NULL, NULL); ?>
153					</li>
154					<li>
155						<?php printLinkHTML($zf . '/admin-logs.php', gettext("Logs"), NULL, NULL, NULL); ?>
156					</li>
157					<?php
158				}
159
160				$gal = getOption('custom_index_page');
161				if (empty($gal) || !file_exists(SERVERPATH . '/' . THEMEFOLDER . '/' . $_zp_gallery->getCurrentTheme() . '/' . internalToFilesystem($gal) . '.php')) {
162					$gal = 'index.php';
163				} else {
164					$gal .= '.php';
165				}
166				$inImage = false;
167				switch ($_zp_gallery_page) {
168					case 'index.php':
169					case $gal:
170						// script is either index.php or the gallery index page
171						if (zp_loggedin(ADMIN_RIGHTS)) {
172							?>
173							<li>
174								<?php printLinkHTML($zf . '/admin-edit.php?page=edit', gettext("Sort Gallery"), NULL, NULL, NULL); ?>
175							</li>
176							<?php
177						}
178						if (zp_loggedin(MANAGE_ALL_ALBUM_RIGHTS)) {
179							// admin has upload rights, provide an upload link for a new album
180							?>
181							<li>
182								<a href="javascript:newAlbum('',true);"><?php echo gettext("New Album"); ?></a>
183							</li>
184							<?php
185						}
186						if ($_zp_gallery_page == 'index.php') {
187							$redirect = '';
188						} else {
189							$redirect = "&amp;p=" . urlencode(stripSuffix($_zp_gallery_page));
190						}
191						if ($page > 1) {
192							$redirect .= "&amp;page=$page";
193						}
194						zp_apply_filter('admin_toolbox_gallery', $zf);
195						break;
196					case 'image.php':
197						$inImage = true; // images are also in albums[sic]
198					case 'album.php':
199						// script is album.php
200						$albumname = $_zp_current_album->name;
201						if ($_zp_current_album->isMyItem(ALBUM_RIGHTS)) {
202							// admin is empowered to edit this album--show an edit link
203							?>
204							<li>
205								<?php printLinkHTML($zf . '/admin-edit.php?page=edit&album=' . pathurlencode($_zp_current_album->name), gettext('Edit album'), NULL, NULL, NULL); ?>
206							</li>
207							<?php
208							if (!$_zp_current_album->isDynamic()) {
209								if ($_zp_current_album->getNumAlbums()) {
210									?>
211									<li>
212										<?php printLinkHTML($zf . '/admin-edit.php?page=edit&album=' . pathurlencode($albumname) . '&tab=subalbuminfo', gettext("Sort subalbums"), NULL, NULL, NULL); ?>
213									</li>
214									<?php
215								}
216								if ($_zp_current_album->getNumImages() > 0) {
217									?>
218									<li>
219										<?php printLinkHTML($zf . '/admin-albumsort.php?page=edit&album=' . pathurlencode($albumname) . '&tab=sort', gettext("Sort images"), NULL, NULL, NULL); ?>
220									</li>
221									<?php
222								}
223							}
224							// and a delete link
225							?>
226							<li>
227								<a href="javascript:confirmDeleteAlbum('<?php echo $zf; ?>/admin-edit.php?page=edit&amp;action=deletealbum&amp;album=<?php echo urlencode(pathurlencode($albumname)) ?>&amp;XSRFToken=<?php echo getXSRFToken('delete'); ?>');"
228									 title="<?php echo gettext('Delete the album'); ?>"><?php echo gettext('Delete album'); ?></a>
229							</li>
230							<?php
231						}
232						if ($_zp_current_album->isMyItem(UPLOAD_RIGHTS) && !$_zp_current_album->isDynamic()) {
233							// provide an album upload link if the admin has upload rights for this album and it is not a dynamic album
234							?>
235							<li>
236								<?php printLinkHTML($zf . '/admin-upload.php?album=' . pathurlencode($albumname), gettext("Upload Here"), NULL, NULL, NULL); ?>
237							</li>
238							<li>
239								<a href="javascript:newAlbum('<?php echo pathurlencode($albumname); ?>',true);"><?php echo gettext("New Album Here"); ?></a>
240							</li>
241							<?php
242						}
243						zp_apply_filter('admin_toolbox_album', $albumname, $zf);
244						if ($inImage) {
245							// script is image.php
246							$imagename = $_zp_current_image->filename;
247								if ($_zp_current_album->isMyItem(ALBUM_RIGHTS)) {
248									if ($_zp_current_album->isDynamic()) { // get folder of the corresponding static album
249										$albumobj = $_zp_current_image->getAlbum();
250										$albumname = $albumobj->name;
251									} else {
252										$delete_image = gettext("Are you sure you want to delete this image? THIS CANNOT BE UNDONE!");
253										// if admin has edit rights on this album, provide a delete link for the image.
254										?>
255										<li>
256											<a href="javascript:confirmDelete('<?php echo $zf; ?>/admin-edit.php?page=edit&amp;action=deleteimage&amp;album=<?php echo urlencode(pathurlencode($albumname)); ?>&amp;image=<?php echo urlencode($imagename); ?>&amp;XSRFToken=<?php echo getXSRFToken('delete'); ?>','<?php echo $delete_image; ?>');"
257												 title="<?php echo gettext("Delete the image"); ?>"><?php echo gettext("Delete image"); ?></a>
258										</li>
259										<?php
260									}
261									?>
262									<li>
263										<a href="<?php echo $zf; ?>/admin-edit.php?page=edit&amp;album=<?php echo pathurlencode($albumname); ?>&amp;singleimage=<?php echo urlencode($imagename); ?>&amp;tab=imageinfo&amp;nopagination"
264											 title="<?php echo gettext('Edit image'); ?>"><?php echo gettext('Edit image'); ?></a>
265									</li>
266									<?php
267								// set return to this image page
268								zp_apply_filter('admin_toolbox_image', $albumname, $imagename, $zf);
269							}
270							$redirect = "&amp;album=" . html_encode(pathurlencode($albumname)) . "&amp;image=" . urlencode($imagename);
271						} else {
272							// set the return to this album/page
273							$redirect = "&amp;album=" . html_encode(pathurlencode($albumname));
274							if ($page > 1) {
275								$redirect .= "&amp;page=$page";
276							}
277						}
278						break;
279					case 'search.php':
280						$words = $_zp_current_search->getSearchWords();
281						if (!empty($words)) {
282							// script is search.php with a search string
283							if (zp_loggedin(UPLOAD_RIGHTS)) {
284								$link = $zf . '/admin-dynamic-album.php?' . substr($_zp_current_search->getSearchParams(), 1);
285								// if admin has edit rights allow him to create a dynamic album from the search
286								?>
287								<li>
288									<a href="<?php echo $link; ?>" title="<?php echo gettext('Create an album from the search'); ?>" ><?php echo gettext('Create Album'); ?></a>
289								</li>
290								<?php
291							}
292							zp_apply_filter('admin_toolbox_search', $zf);
293						}
294						$redirect = "&amp;p=search" . $_zp_current_search->getSearchParams() . "&amp;page=$page";
295						break;
296					default:
297						// arbitrary custom page
298						$gal = stripSuffix($_zp_gallery_page);
299						$redirect = "&amp;p=" . urlencode($gal);
300						if ($page > 1) {
301							$redirect .= "&amp;page=$page";
302						}
303						$redirect = zp_apply_filter('admin_toolbox_' . $gal, $redirect, $zf);
304						break;
305				}
306				$redirect = zp_apply_filter('admin_toolbox_close', $redirect, $zf);
307				if ($_zp_current_admin_obj->logout_link) {
308					// logout link
309					$sec = (int) ((SERVER_PROTOCOL == 'https') & true);
310					$link = SEO_FULLWEBPATH . '/index.php?logout=' . $sec . $redirect;
311					?>
312					<li>
313						<?php printLinkHTML($link, gettext("Logout"), gettext("Logout"), null, null); ?>
314					</li>
315					<?php
316				}
317				$outputB = ob_get_contents();
318				ob_end_clean();
319				if ($outputB) {
320					echo $outputA . $outputB;
321					?>
322				</ul>
323			</div>
324		</div>
325		<?php
326		}
327	}
328}
329
330//*** Gallery Index (album list) Context ***
331//******************************************
332
333/**
334 * Returns the raw title of the gallery.
335 *
336 * @return string
337 */
338function getGalleryTitle() {
339	global $_zp_gallery;
340	return $_zp_gallery->getTitle();
341}
342
343/**
344 * Returns a text-only title of the gallery.
345 *
346 * @return string
347 */
348function getBareGalleryTitle() {
349	return getBare(getGalleryTitle());
350}
351
352/**
353 * Prints the title of the gallery.
354 */
355function printGalleryTitle() {
356	echo html_encodeTagged(getGalleryTitle());
357}
358
359function printBareGalleryTitle() {
360	echo html_encode(getBareGalleryTitle());
361}
362
363/**
364 * Function to create the page title to be used within the html <head> <title></title> element.
365 * Usefull if you use one header.php for the header of all theme pages instead of individual ones on the theme pages
366 * It returns the title and site name in reversed breadcrumb order:
367 * <title of current page> | <parent item if present> | <gallery title>
368 * It supports standard gallery pages as well a custom and Zenpage news articles, categories and pages.
369 *
370 * @param string $separator How you wish the parts to be separated
371 * @param bool $listparentalbums If the parent albums should be printed in reversed order before the current
372 * @param bool $listparentpage If the parent Zenpage pages should be printed in reversed order before the current page
373 */
374function getHeadTitle($separator = ' | ', $listparentalbums = true, $listparentpages = true) {
375	global $_zp_gallery, $_zp_current_album, $_zp_current_image, $_zp_current_zenpage_news, $_zp_current_zenpage_page, $_zp_gallery_page, $_zp_current_category, $_zp_page, $_myFavorites;
376	$mainsitetitle = html_encode(getBare(getMainSiteName()));
377	$separator = html_encode($separator);
378	if ($mainsitetitle) {
379		$mainsitetitle = $separator . $mainsitetitle;
380	}
381	$gallerytitle = html_encode(getBareGalleryTitle());
382	if ($_zp_page > 1) {
383		$pagenumber = ' (' . $_zp_page . ')';
384	} else {
385		$pagenumber = '';
386	}
387	switch ($_zp_gallery_page) {
388		case 'index.php':
389			return $gallerytitle . $mainsitetitle . $pagenumber;
390			break;
391		case 'album.php':
392		case 'image.php':
393			if ($listparentalbums) {
394				$parents = getParentAlbums();
395				$parentalbums = '';
396				if (count($parents) != 0) {
397					$parents = array_reverse($parents);
398					foreach ($parents as $parent) {
399						$parentalbums .= html_encode(getBare($parent->getTitle())) . $separator;
400					}
401				}
402			} else {
403				$parentalbums = '';
404			}
405			$albumtitle = html_encode(getBareAlbumTitle()) . $pagenumber . $separator . $parentalbums . $gallerytitle . $mainsitetitle;
406			switch ($_zp_gallery_page) {
407				case 'album.php':
408					return $albumtitle;
409					break;
410				case 'image.php':
411					return html_encode(getBareImageTitle()) . $separator . $albumtitle;
412					break;
413			}
414			break;
415		case 'news.php':
416			if (function_exists("is_NewsArticle")) {
417				if (is_NewsArticle()) {
418					return html_encode(getBareNewsTitle()) . $pagenumber . $separator . gettext('News') . $separator . $gallerytitle . $mainsitetitle;
419				} else if (is_NewsCategory()) {
420					return html_encode(getBare($_zp_current_category->getTitle())) . $pagenumber . $separator . gettext('News') . $separator . $gallerytitle . $mainsitetitle;
421				} else {
422					return gettext('News') . $pagenumber . $separator . $gallerytitle . $mainsitetitle;
423				}
424			}
425			break;
426		case 'pages.php':
427			if ($listparentpages) {
428				$parents = $_zp_current_zenpage_page->getParents();
429				$parentpages = '';
430				if (count($parents) != 0) {
431					$parents = array_reverse($parents);
432					foreach ($parents as $parent) {
433						$obj = new ZenpagePage($parent);
434						$parentpages .= html_encode(getBare($obj->getTitle())) . $separator;
435					}
436				}
437			} else {
438				$parentpages = '';
439			}
440			return html_encode(getBarePageTitle()) . $pagenumber . $separator . $parentpages . $gallerytitle . $mainsitetitle;
441			break;
442		case '404.php':
443			return gettext('Object not found') . $separator . $gallerytitle . $mainsitetitle;
444			break;
445		default: // for all other possible static custom pages
446			$custompage = stripSuffix($_zp_gallery_page);
447			$standard = array(
448					'gallery' => gettext('Gallery'),
449					'contact' => gettext('Contact'),
450					'register' => gettext('Register'),
451					'search' => gettext('Search'),
452					'archive' => gettext('Archive view'),
453					'password' => gettext('Password required'));
454			if (is_object($_myFavorites)) {
455				$standard['favorites'] = gettext('My favorites');
456			}
457			if (array_key_exists($custompage, $standard)) {
458				return $standard[$custompage] . $pagenumber . $separator . $gallerytitle . $mainsitetitle;
459			} else {
460				return $custompage . $pagenumber . $separator . $gallerytitle . $mainsitetitle;
461			}
462			break;
463	}
464}
465
466/**
467 * Function to print the html <title>title</title> within the <head> of a html page based on the current theme page
468 * Usefull if you use one header.php for the header of all theme pages instead of individual ones on the theme pages
469 * It prints the title and site name including the <title> tag in reversed breadcrumb order:
470 * <title><title of current page> | <parent item if present> | <gallery title></title>
471 * It supports standard gallery pages as well a custom and Zenpage news articles, categories and pages.
472 *
473 * @param string $separator How you wish the parts to be separated
474 * @param bool $listparentalbums If the parent albums should be printed in reversed order before the current
475 * @param bool $listparentpage If the parent Zenpage pages should be printed in reversed order before the current page
476 */
477function printHeadTitle($separator = ' | ', $listparentalbums = true, $listparentpages = true) {
478	echo '<title>' . getHeadTitle($separator, $listparentalbums, $listparentpages) . '</title>';
479}
480
481/**
482 * Returns the raw description of the gallery.
483 *
484 * @return string
485 */
486function getGalleryDesc() {
487	global $_zp_gallery;
488	return $_zp_gallery->getDesc();
489}
490
491/**
492 * Returns a text-only description of the gallery.
493 *
494 * @return string
495 */
496function getBareGalleryDesc() {
497	return getBare(getGalleryDesc());
498}
499
500/**
501 * Prints the description of the gallery.
502 */
503function printGalleryDesc() {
504	echo html_encodeTagged(getGalleryDesc());
505}
506
507function printBareGalleryDesc() {
508	echo html_encode(getBareGalleryDesc());
509}
510
511/**
512 * Returns the name of the main website as set by the "Website Title" option
513 * on the gallery options tab. Use this if Zenphoto is only a part of your website.
514 *
515 * @return string
516 */
517function getMainSiteName() {
518	global $_zp_gallery;
519	return $_zp_gallery->getWebsiteTitle();
520}
521
522/**
523 * Returns the URL of the main website as set by the "Website URL" option
524 * on the gallery options tab. Use this if Zenphoto is only a part of your website.
525 *
526 * @return string
527 */
528function getMainSiteURL() {
529	global $_zp_gallery;
530	return $_zp_gallery->getWebsiteURL();
531}
532
533/**
534 * Returns the URL of the main gallery index page. If a custom index page is set this returns that page.
535 * So this is not necessarily the home page of the site!
536 * @return string
537 */
538function getGalleryIndexURL() {
539	global $_zp_current_album, $_zp_gallery_page;
540	$page = 1;
541	if (in_context(ZP_ALBUM) && $_zp_gallery_page != 'index.php') {
542		$album = getUrAlbum($_zp_current_album);
543		$page = $album->getGalleryPage();
544	}
545	if (!$link = getCustomGalleryIndexURL($page)) {
546		$link = getStandardGalleryIndexURL($page);
547	}
548	return zp_apply_filter('getLink', $link, 'index.php', NULL);
549}
550
551/**
552 * Returns the url to the standard gallery index.php page
553 *
554 * @see getGalleryIndexURL()
555 *
556 * @param int $page Pagenumber to append
557 * @param bool $webpath host path to be prefixed. If "false" is passed you will get a localized "WEBPATH"
558 * @return string
559 */
560function getStandardGalleryIndexURL($page = 1, $webpath = null) {
561	if ($page > 1) {
562		return rewrite_path('/' . _PAGE_ . '/' . $page . '/', "/index.php?" . "page=" . $page, $webpath);
563	} else {
564		if (is_null($webpath)) {
565			if (class_exists('seo_locale')) {
566				$webpath = seo_locale::localePath();
567			} else {
568				$webpath = WEBPATH;
569			}
570		}
571		return $webpath . "/";
572	}
573}
574
575/**
576 * Gets the custom gallery index url if one is set, otherwise false
577 *
578 * @see getGalleryIndexURL()
579 *
580 * @global array $_zp_conf_vars
581 * @param int $page Pagenumber for pagination
582 * @param bool $webpath host path to be prefixed. If "false" is passed you will get a localized "WEBPATH"
583 * @return string
584 */
585function getCustomGalleryIndexURL($page = 1, $webpath = null) {
586	$custom_index = getOption('custom_index_page');
587	if ($custom_index) {
588		$link = getCustomPageURL($custom_index, '', $webpath);
589		if ($page > 1) {
590			if (MOD_REWRITE) {
591				$link .= $page . '/';
592			} else {
593				$link .= "&amp;page=" . $page;
594			}
595		}
596		return $link;
597	}
598	return false;
599}
600
601/**
602 * Returns the name to the individual custom gallery index page name if set,
603 * otherwise returns generic custom gallery page "gallery.php" that is widely supported by themes
604 * If you need to check if there is an indovidual custom_index_page set use
605 * `getOption('custom_index_page')` or `getCustomGalleryIndexURL()`
606 *
607 * @return string
608 */
609function getCustomGalleryIndexPage() {
610	$custom_index = getOption('custom_index_page');
611	if ($custom_index) {
612		return $custom_index . '.php';
613	}
614	return 'gallery.php';
615}
616
617/**
618 * If a custom gallery index page is set this first prints a link to the actual site index (home page = index.php)
619 * followed by the gallery index page link. Otherwise just the gallery index link
620 *
621 * @since 1.4.9
622 * @param string $after Text to append after and outside the link for breadcrumbs
623 * @param string $text Name of the link, if NULL "Gallery" is used
624 * @param bool $printHomeURL In case of a custom gallery index, display breadcrumb with home link (default is true)
625 */
626function printGalleryIndexURL($after = NULL, $text = NULL, $printHomeURL = true) {
627	global $_zp_gallery_page;
628	if (is_null($text)) {
629		$text = gettext('Gallery');
630	}
631	$customgalleryindex = getOption('custom_index_page');
632	if ($customgalleryindex && $printHomeURL) {
633		printSiteHomeURL($after);
634	}
635	if ($_zp_gallery_page == getCustomGalleryIndexPage()) {
636		$after = NULL;
637	}
638	if (!$customgalleryindex || ($customgalleryindex && in_array($_zp_gallery_page, array('image.php', 'album.php', getCustomGalleryIndexPage())))) {
639		printLinkHTML(getGalleryIndexURL(), $text, $text, 'galleryindexurl');
640		echo $after;
641	}
642}
643
644
645/**
646 * Returns the home page link (WEBPATH) to the Zenphoto theme index.php page
647 * Use in breadcrumbs if the theme uses a custom gallery index page so the gallery is not the site's home page
648 *
649 * @since 1.4.9
650 * @global string $_zp_gallery_page
651 * @return string
652 */
653function getSiteHomeURL() {
654	return WEBPATH . '/';
655}
656
657/**
658 * Prints the home page link (WEBPATH with trailing slash) to a Zenphoto theme index.php page
659 * Use in breadcrumbs if the theme uses a custom gallery index page so the gallery is not the site's home page
660 *
661 * @param string $after Text after and outside the link for breadcrumbs
662 * @param string $text Text of the link, if NULL "Home"
663 */
664function printSiteHomeURL($after = NULL, $text = NULL) {
665	global $_zp_gallery_page;
666	if ($_zp_gallery_page == 'index.php') {
667		$after = '';
668	}
669	if (is_null($text)) {
670		$text = gettext('Home');
671	}
672	printLinkHTML(getSiteHomeURL(), $text, $text, 'homeurl');
673	echo $after;
674}
675
676/**
677 * If the privacy page url option is set this prints a link to it
678 * @param string $before To print before the link
679 * @param string $after To print after the link
680 */
681function printPrivacyPageLink($before = null, $after = null) {
682	$data = getDataUsageNotice();
683	if (!empty($data['url'])) {
684		echo $before;
685		printLinkHTML($data['url'], $data['linktext'], $data['linktext'], null, null);
686		echo $after;
687	}
688}
689
690/**
691 * Returns the number of albums.
692 *
693 * @return int
694 */
695function getNumAlbums() {
696	global $_zp_gallery, $_zp_current_album, $_zp_current_search;
697	if (in_context(ZP_SEARCH) && is_null($_zp_current_album)) {
698		return $_zp_current_search->getNumAlbums();
699	} else if (in_context(ZP_ALBUM)) {
700		return $_zp_current_album->getNumAlbums();
701	} else {
702		return $_zp_gallery->getNumAlbums();
703	}
704}
705
706/**
707 * Returns the name of the currently active theme
708 *
709 * @return string
710 */
711function getCurrentTheme() {
712	global $_zp_gallery;
713	return $_zp_gallery->getCurrentTheme();
714}
715
716/* * * Album AND Gallery Context *********** */
717/* * *************************************** */
718
719/**
720 * WHILE next_album(): context switches to Album.
721 * If we're already in the album context, this is a sub-albums loop, which,
722 * quite simply, changes the source of the album list.
723 * Switch back to the previous context when there are no more albums.
724
725 * Returns true if there are albums, false if none
726 *
727 * @param bool $all true to go through all the albums
728 * @param bool $mine override the password checks
729 * @return bool
730 * @since 0.6
731 */
732function next_album($all = false, $mine = NULL) {
733	global $_zp_albums, $_zp_gallery, $_zp_current_album, $_zp_page, $_zp_current_album_restore, $_zp_current_search;
734	if (is_null($_zp_albums)) {
735		if (in_context(ZP_SEARCH)) {
736			$_zp_albums = $_zp_current_search->getAlbums($all ? 0 : $_zp_page, NULL, NULL, true, $mine);
737		} else if (in_context(ZP_ALBUM)) {
738			$_zp_albums = $_zp_current_album->getAlbums($all ? 0 : $_zp_page, NULL, NULL, true, $mine);
739		} else {
740			$_zp_albums = $_zp_gallery->getAlbums($all ? 0 : $_zp_page, NULL, NULL, true, $mine);
741		}
742		if (empty($_zp_albums)) {
743			return NULL;
744		}
745		$_zp_current_album_restore = $_zp_current_album;
746		$_zp_current_album = newAlbum(array_shift($_zp_albums), true, true);
747		save_context();
748		add_context(ZP_ALBUM);
749		return true;
750	} else if (empty($_zp_albums)) {
751		$_zp_albums = NULL;
752		$_zp_current_album = $_zp_current_album_restore;
753		restore_context();
754		return false;
755	} else {
756		$_zp_current_album = newAlbum(array_shift($_zp_albums), true, true);
757		return true;
758	}
759}
760
761/**
762 * Returns the number of the current page without printing it.
763 *
764 * @return int
765 */
766function getCurrentPage() {
767	global $_zp_page;
768	return $_zp_page;
769}
770
771/**
772 * Gets an array of the album ids of all accessible albums (publich or user dependend)
773 *
774 * @param object $obj from whence to get the albums
775 * @param array $albumlist collects the list
776 * @param bool $scan force scan for new images in the album folder
777 */
778function getAllAccessibleAlbums($obj, &$albumlist, $scan) {
779	global $_zp_gallery;
780	$locallist = $obj->getAlbums();
781 foreach ($locallist as $folder) {
782		$album = newAlbum($folder);
783		If (!$album->isDynamic() && $album->checkAccess()) {
784			if ($scan)
785				$album->getImages();
786			$albumlist[] = $album->getID();
787			getAllAccessibleAlbums($album, $albumlist, $scan);
788		}
789	}
790}
791
792/**
793 * Returns the number of pages for the current object
794 *
795 * @param bool $_oneImagePage set to true if your theme collapses all image thumbs
796 * or their equivalent to one page. This is typical with flash viewer themes
797 *
798 * @return int
799 */
800function getTotalPages($_oneImagePage = false) {
801	global $_zp_gallery, $_zp_current_album, $_firstPageImages, $_zp_zenpage, $_zp_current_category;
802	if (in_context(ZP_ALBUM | ZP_SEARCH)) {
803		$albums_per_page = max(1, getOption('albums_per_page'));
804		$pageCount = (int) ceil(getNumAlbums() / $albums_per_page);
805		$imageCount = getNumImages();
806		if ($_oneImagePage) {
807			if ($_oneImagePage === true) {
808				$imageCount = min(1, $imageCount);
809			} else {
810				$imageCount = 0;
811			}
812		}
813		$images_per_page = max(1, getOption('images_per_page'));
814		$pageCount = ($pageCount + ceil(($imageCount - $_firstPageImages) / $images_per_page));
815		return $pageCount;
816	} else if (get_context() == ZP_INDEX) {
817		if (galleryAlbumsPerPage() != 0) {
818			return (int) ceil($_zp_gallery->getNumAlbums() / galleryAlbumsPerPage());
819		} else {
820			return NULL;
821		}
822		return NULL;
823	} else if (isset($_zp_zenpage)) {
824		if (in_context(ZP_ZENPAGE_NEWS_CATEGORY)) {
825			$cat = $_zp_current_category;
826		} else {
827			$cat = NULL;
828		}
829		return (int) ceil(count($_zp_zenpage->getArticles(0, NULL, true, NULL, NULL, NULL, $cat)) / ZP_ARTICLES_PER_PAGE);
830	}
831}
832
833/**
834 * Returns the URL of the page number passed as a parameter
835 *
836 * @param int $page Which page is desired
837 * @param int $total How many pages there are.
838 * @return int
839 */
840function getPageNumURL($page, $total = null) {
841	global $_zp_current_album, $_zp_gallery, $_zp_current_search, $_zp_gallery_page, $_zp_conf_vars;
842	if (is_null($total)) {
843		$total = getTotalPages();
844	}
845	if ($page <= 0 || $page > $total) {
846		return NULL;
847	}
848	if (in_context(ZP_SEARCH)) {
849		$searchwords = $_zp_current_search->codifySearchString();
850		$searchdate = $_zp_current_search->getSearchDate();
851		$searchfields = $_zp_current_search->getSearchFields(true);
852		$searchpagepath = getSearchURL($searchwords, $searchdate, $searchfields, $page, array('albums' => $_zp_current_search->getAlbumList()));
853		return $searchpagepath;
854	} else if (in_context(ZP_ALBUM)) {
855		return $_zp_current_album->getLink($page);
856	} else if (in_array($_zp_gallery_page, array('index.php', 'album.php', 'image.php'))) {
857		if (in_context(ZP_INDEX)) {
858			$pagination1 = '/';
859			$pagination2 = 'index.php';
860			if ($page > 1) {
861				$pagination1 .= _PAGE_ . '/' . $page . '/';
862				$pagination2 .= '?page=' . $page;
863			}
864		} else {
865			return NULL;
866		}
867	} else {
868		// handle custom page
869		$pg = stripSuffix($_zp_gallery_page);
870		if (array_key_exists($pg, $_zp_conf_vars['special_pages'])) {
871			$pagination1 = preg_replace('~^_PAGE_/~', _PAGE_ . '/', $_zp_conf_vars['special_pages'][$pg]['rewrite']) . '/';
872		} else {
873			$pagination1 = '/' . _PAGE_ . '/' . $pg . '/';
874		}
875		$pagination2 = 'index.php?p=' . $pg;
876		if ($page > 1) {
877			$pagination1 .= $page . '/';
878			$pagination2 .= '&page=' . $page;
879		}
880	}
881	return zp_apply_filter('getLink', rewrite_path($pagination1, $pagination2), $_zp_gallery_page, $page);
882}
883
884/**
885 * Returns true if there is a next page
886 *
887 * @return bool
888 */
889function hasNextPage() {
890	return (getCurrentPage() < getTotalPages());
891}
892
893/**
894 * Returns the URL of the next page. Use within If or while loops for pagination.
895 *
896 * @return string
897 */
898function getNextPageURL() {
899	return getPageNumURL(getCurrentPage() + 1);
900}
901
902/**
903 * Prints the URL of the next page.
904 *
905 * @param string $text text for the URL
906 * @param string $title Text for the HTML title
907 * @param string $class Text for the HTML class
908 * @param string $id Text for the HTML id
909 */
910function printNextPageURL($text, $title = NULL, $class = NULL, $id = NULL) {
911	if (hasNextPage()) {
912		printLinkHTML(getNextPageURL(), $text, $title, $class, $id);
913	} else {
914		echo "<span class=\"disabledlink\">$text</span>";
915	}
916}
917
918/**
919 * Returns TRUE if there is a previous page. Use within If or while loops for pagination.
920 *
921 * @return bool
922 */
923function hasPrevPage() {
924	return (getCurrentPage() > 1);
925}
926
927/**
928 * Returns the URL of the previous page.
929 *
930 * @return string
931 */
932function getPrevPageURL() {
933	return getPageNumURL(getCurrentPage() - 1);
934}
935
936/**
937 * Returns the URL of the previous page.
938 *
939 * @param string $text The linktext that should be printed as a link
940 * @param string $title The text the html-tag "title" should contain
941 * @param string $class Insert here the CSS-class name you want to style the link with
942 * @param string $id Insert here the CSS-ID name you want to style the link with
943 */
944function printPrevPageURL($text, $title = NULL, $class = NULL, $id = NULL) {
945	if (hasPrevPage()) {
946		printLinkHTML(getPrevPageURL(), $text, $title, $class, $id);
947	} else {
948		echo "<span class=\"disabledlink\">$text</span>";
949	}
950}
951
952/**
953 * Prints a page navigation including previous and next page links
954 *
955 * @param string $prevtext Insert here the linktext like 'previous page'
956 * @param string $separator Insert here what you like to be shown between the prev and next links
957 * @param string $nexttext Insert here the linktext like "next page"
958 * @param string $class Insert here the CSS-class name you want to style the link with (default is "pagelist")
959 * @param string $id Insert here the CSS-ID name if you want to style the link with this
960 */
961function printPageNav($prevtext, $separator, $nexttext, $class = 'pagenav', $id = NULL) {
962	echo "<div" . (($id) ? " id=\"$id\"" : "") . " class=\"$class\">";
963	printPrevPageURL($prevtext, gettext("Previous Page"));
964	echo " $separator ";
965	printNextPageURL($nexttext, gettext("Next Page"));
966	echo "</div>\n";
967}
968
969/**
970 * Prints a list of all pages.
971 *
972 * @param string $class the css class to use, "pagelist" by default
973 * @param string $id the css id to use
974 * @param int $navlen Number of navigation links to show (0 for all pages). Works best if the number is odd.
975 */
976function printPageList($class = 'pagelist', $id = NULL, $navlen = 9) {
977	printPageListWithNav(null, null, false, false, $class, $id, false, $navlen);
978}
979
980/**
981 * returns a page nav list.
982 *
983 * @param bool $_oneImagePage set to true if there is only one image page as, for instance, in flash themes
984 * @param int $navlen Number of navigation links to show (0 for all pages). Works best if the number is odd.
985 * @param bool $firstlast Add links to the first and last pages of you gallery
986 * @param int $current the current page
987 * @param int $total total number of pages
988 *
989 */
990function getPageNavList($_oneImagePage, $navlen, $firstlast, $current, $total) {
991	$result = array();
992	if (hasPrevPage()) {
993		$result['prev'] = getPrevPageURL();
994	} else {
995		$result['prev'] = NULL;
996	}
997	if ($firstlast) {
998		$result[1] = getPageNumURL(1, $total);
999	}
1000
1001	if ($navlen == 0) {
1002		$navlen = $total;
1003	}
1004	$extralinks = 2;
1005	if ($firstlast)
1006		$extralinks = $extralinks + 2;
1007	$len = floor(($navlen - $extralinks) / 2);
1008	$j = max(round($extralinks / 2), min($current - $len - (2 - round($extralinks / 2)), $total - $navlen + $extralinks - 1));
1009	$ilim = min($total, max($navlen - round($extralinks / 2), $current + floor($len)));
1010	$k1 = round(($j - 2) / 2) + 1;
1011	$k2 = $total - round(($total - $ilim) / 2);
1012
1013	for ($i = $j; $i <= $ilim; $i++) {
1014		$result[$i] = getPageNumURL($i, $total);
1015	}
1016	if ($firstlast) {
1017		$result[$total] = getPageNumURL($total, $total);
1018	}
1019	if (hasNextPage()) {
1020		$result['next'] = getNextPageURL();
1021	} else {
1022		$result['next'] = NULL;
1023	}
1024	return $result;
1025}
1026
1027/**
1028 * Prints a full page navigation including previous and next page links with a list of all pages in between.
1029 *
1030 * @param string $prevtext Insert here the linktext like 'previous page'
1031 * @param string $nexttext Insert here the linktext like 'next page'
1032 * @param bool $_oneImagePage set to true if there is only one image page as, for instance, in flash themes
1033 * @param string $nextprev set to true to get the 'next' and 'prev' links printed
1034 * @param string $class Insert here the CSS-class name you want to style the link with (default is "pagelist")
1035 * @param string $id Insert here the CSS-ID name if you want to style the link with this
1036 * @param bool $firstlast Add links to the first and last pages of you gallery
1037 * @param int $navlen Number of navigation links to show (0 for all pages). Works best if the number is odd.
1038 */
1039function printPageListWithNav($prevtext, $nexttext, $_oneImagePage = false, $nextprev = true, $class = 'pagelist', $id = NULL, $firstlast = true, $navlen = 9) {
1040	$current = getCurrentPage();
1041	$total = max(1, getTotalPages($_oneImagePage));
1042	$nav = getPageNavList($_oneImagePage, $navlen, $firstlast, $current, $total);
1043	if ($total > 1) {
1044		?>
1045		<div <?php if ($id) echo ' id="'.$id.'"'; ?> class="<?php echo $class; ?>">
1046			<ul class="<?php echo $class; ?>">
1047				<?php
1048				$prev = $nav['prev'];
1049				unset($nav['prev']);
1050				$next = $nav['next'];
1051				unset($nav['next']);
1052				if ($nextprev) {
1053					?>
1054					<li class="prev">
1055						<?php
1056						if ($prev) {
1057							printLinkHTML($prev, html_encode($prevtext), gettext('Previous Page'));
1058						} else {
1059							?>
1060							<span class="disabledlink"><?php echo html_encode($prevtext); ?></span>
1061							<?php
1062						}
1063						?>
1064					</li>
1065					<?php
1066				}
1067				$last = NULL;
1068				if ($firstlast) {
1069					?>
1070					<li class="<?php
1071					if ($current == 1)
1072						echo 'current';
1073					else
1074						echo 'first';
1075					?>">
1076								<?php
1077								if ($current == 1) {
1078									echo '1';
1079								} else {
1080									printLinkHTML($nav[1], 1, gettext("Page 1"));
1081								}
1082								?>
1083					</li>
1084					<?php
1085					$last = 1;
1086					unset($nav[1]);
1087				}
1088				foreach ($nav as $i => $link) {
1089					$d = $i - $last;
1090					if ($d > 2) {
1091						?>
1092						<li>
1093							<?php
1094							$k1 = $i - (int) (($i - $last) / 2);
1095							printLinkHTML(getPageNumURL($k1, $total), '...', sprintf(ngettext('Page %u', 'Page %u', $k1), $k1));
1096							?>
1097						</li>
1098						<?php
1099					} else if ($d == 2) {
1100						?>
1101						<li>
1102							<?php
1103							$k1 = $last + 1;
1104							printLinkHTML(getPageNumURL($k1, $total), $k1, sprintf(ngettext('Page %u', 'Page %u', $k1), $k1));
1105							?>
1106						</li>
1107						<?php
1108					}
1109					?>
1110					<li<?php if ($current == $i) echo ' class="current"'; ?>>
1111						<?php
1112						if ($i == $current) {
1113							echo $i;
1114						} else {
1115							$title = sprintf(ngettext('Page %1$u', 'Page %1$u', $i), $i);
1116							printLinkHTML($link, $i, $title);
1117						}
1118						?>
1119					</li>
1120					<?php
1121					$last = $i;
1122					unset($nav[$i]);
1123					if ($firstlast && count($nav) == 1) {
1124						break;
1125					}
1126				}
1127				if ($firstlast) {
1128					foreach ($nav as $i => $link) {
1129						$d = $i - $last;
1130						if ($d > 2) {
1131							$k1 = $i - (int) (($i - $last) / 2);
1132							?>
1133							<li>
1134								<?php printLinkHTML(getPageNumURL($k1, $total), '...', sprintf(ngettext('Page %u', 'Page %u', $k1), $k1)); ?>
1135							</li>
1136							<?php
1137						} else if ($d == 2) {
1138							$k1 = $last + 1;
1139							?>
1140							<li>
1141								<?php printLinkHTML(getPageNumURL($k1, $total), $k1, sprintf(ngettext('Page %u', 'Page %u', $k1), $k1)); ?>
1142							</li>
1143							<?php
1144						}
1145						?>
1146						<li class="last<?php if ($current == $i) echo ' current'; ?>">
1147							<?php
1148							if ($current == $i) {
1149								echo $i;
1150							} else {
1151								printLinkHTML($link, $i, sprintf(ngettext('Page %u', 'Page %u', $i), $i));
1152							}
1153							?>
1154						</li>
1155						<?php
1156					}
1157				}
1158				if ($nextprev) {
1159					?>
1160					<li class="next">
1161						<?php
1162						if ($next) {
1163							printLinkHTML($next, html_encode($nexttext), gettext('Next Page'));
1164						} else {
1165							?>
1166							<span class="disabledlink"><?php echo html_encode($nexttext); ?></span>
1167							<?php
1168						}
1169						?>
1170					</li>
1171					<?php
1172				}
1173				?>
1174			</ul>
1175		</div>
1176		<?php
1177	}
1178}
1179
1180//*** Album Context ************************
1181//******************************************
1182
1183/**
1184 * Sets the album passed as the current album
1185 *
1186 * @param object $album the album to be made current
1187 */
1188function makeAlbumCurrent($album) {
1189	global $_zp_current_album;
1190	$_zp_current_album = $album;
1191	set_context(ZP_INDEX | ZP_ALBUM);
1192}
1193
1194/**
1195 * Returns the raw title of the current album.
1196 *
1197 * @return string
1198 */
1199function getAlbumTitle() {
1200	if (!in_context(ZP_ALBUM))
1201		return false;
1202	global $_zp_current_album;
1203	return $_zp_current_album->getTitle();
1204}
1205
1206/**
1207 * Returns a text-only title of the current album.
1208 *
1209 * @return string
1210 */
1211function getBareAlbumTitle() {
1212	return getBare(getAlbumTitle());
1213}
1214
1215/**
1216 * Returns an album title taged with of Not visible or password protected status
1217 *
1218 * @return string;
1219 */
1220function getAnnotatedAlbumTitle() {
1221	global $_zp_current_album;
1222	$title = getBareAlbumTitle();
1223	$pwd = $_zp_current_album->getPassword();
1224	if (zp_loggedin() && !empty($pwd)) {
1225		$title .= "\n" . gettext('The album is password protected.');
1226	}
1227	if (!$_zp_current_album->isPublished()) {
1228		$title .= "\n" . gettext('The album is un-published.');
1229	}
1230	return $title;
1231}
1232
1233function printAnnotatedAlbumTitle() {
1234	echo html_encode(getAnnotatedAlbumTitle());
1235}
1236
1237/**
1238 * Prints an encapsulated title of the current album.
1239 * If you are logged in you can click on this to modify the title on the fly.
1240 *
1241 * @author Ozh
1242 */
1243function printAlbumTitle() {
1244	echo html_encodeTagged(getAlbumTitle());
1245}
1246
1247function printBareAlbumTitle() {
1248	echo html_encodeTagged(getBareAlbumTitle());
1249}
1250
1251/**
1252 * Gets the 'n' for n of m albums
1253 *
1254 * @return int
1255 */
1256function albumNumber() {
1257	global $_zp_current_album, $_zp_current_image, $_zp_current_search, $_zp_gallery;
1258	$name = $_zp_current_album->getFileName();
1259	if (in_context(ZP_SEARCH)) {
1260		$albums = $_zp_current_search->getAlbums();
1261	} else if (in_context(ZP_ALBUM)) {
1262		$parent = $_zp_current_album->getParent();
1263		if (is_null($parent)) {
1264			$albums = $_zp_gallery->getAlbums();
1265		} else {
1266			$albums = $parent->getAlbums();
1267		}
1268	}
1269	$c = 0;
1270	foreach ($albums as $albumfolder) {
1271		$c++;
1272		if ($name == $albumfolder) {
1273			return $c;
1274		}
1275	}
1276	return false;
1277}
1278
1279/**
1280 * Returns an array of the names of the parents of the current album.
1281 *
1282 * @param object $album optional album object to use inseted of the current album
1283 * @return array
1284 */
1285function getParentAlbums($album = null) {
1286	$parents = array();
1287	if (in_context(ZP_ALBUM)) {
1288		global $_zp_current_album, $_zp_current_search, $_zp_gallery;
1289		if (is_null($album)) {
1290			if (in_context(ZP_SEARCH_LINKED) && !in_context(ZP_ALBUM_LINKED)) {
1291				$album = $_zp_current_search->getDynamicAlbum();
1292				if (empty($album))
1293					return $parents;
1294			} else {
1295				$album = $_zp_current_album;
1296			}
1297		}
1298		while (!is_null($album = $album->getParent())) {
1299			array_unshift($parents, $album);
1300		}
1301	}
1302	return $parents;
1303}
1304
1305/**
1306 * returns the breadcrumb item for the current images's album
1307 *
1308 * @param string $title Text to be used as the URL title tag
1309 * @return array
1310 */
1311function getAlbumBreadcrumb($title = NULL) {
1312	global $_zp_current_search, $_zp_gallery, $_zp_current_album, $_zp_last_album;
1313	$output = array();
1314	if (in_context(ZP_SEARCH_LINKED)) {
1315		$album = NULL;
1316		$dynamic_album = $_zp_current_search->getDynamicAlbum();
1317		if (empty($dynamic_album)) {
1318			if (!is_null($_zp_current_album)) {
1319				if (in_context(ZP_ALBUM_LINKED) && $_zp_last_album == $_zp_current_album->name) {
1320					$album = $_zp_current_album;
1321				}
1322			}
1323		} else {
1324			if (in_context(ZP_IMAGE) && in_context(ZP_ALBUM_LINKED)) {
1325				$album = $_zp_current_album;
1326			} else {
1327				$album = $dynamic_album;
1328			}
1329		}
1330	} else {
1331		$album = $_zp_current_album;
1332	}
1333	if ($album) {
1334		if (is_null($title)) {
1335			$title = $album->getTitle();
1336			if (empty($title)) {
1337				$title = gettext('Album Thumbnails');
1338			}
1339		}
1340		return array('link' => $album->getLink(), 'text' => $title, 'title' => getBare($title));
1341	}
1342	return false;
1343}
1344
1345/**
1346 * prints the breadcrumb item for the current images's album
1347 *
1348 * @param string $before Text to place before the breadcrumb
1349 * @param string $after Text to place after the breadcrumb
1350 * @param string $title Text to be used as the URL title attribute and text link
1351 */
1352function printAlbumBreadcrumb($before = '', $after = '', $title = NULL) {
1353	if ($breadcrumb = getAlbumBreadcrumb($title)) {
1354		if ($before) {
1355			$output = '<span class="beforetext">' . html_encode($before) . '</span>';
1356		} else {
1357			$output = '';
1358		}
1359		$output .= '<a href="' . html_encode($breadcrumb['link']) . '" title="' . html_encode($breadcrumb['title']) . '">';
1360		$output .= html_encode($breadcrumb['text']);
1361		$output .= '</a>';
1362		if ($after) {
1363			$output .= '<span class="aftertext">' . html_encode($after) . '</span>';
1364		}
1365		echo $output;
1366	}
1367}
1368
1369/**
1370 * Prints the "breadcrumb" for a search page
1371 * 		if the search was for a data range, the breadcrumb is "Archive"
1372 * 		otherwise it is "Search"
1373 * @param string $between Insert here the text to be printed between the links
1374 * @param string $class is the class for the link (if present)
1375 * @param string $search text for a search page title
1376 * @param string $archive text for an archive page title
1377 * @param string $format data format for archive page crumb
1378 */
1379function printSearchBreadcrumb($between = NULL, $class = NULL, $search = NULL, $archive = NULL, $format = '%B %Y') {
1380	global $_zp_current_search;
1381	if (is_null($between)) {
1382		$between = ' | ';
1383	}
1384	if ($class) {
1385		$class = ' class="' . $class . '"';
1386	}
1387	if ($d = $_zp_current_search->getSearchDate()) {
1388		if (is_null($archive)) {
1389			$text = gettext('Archive');
1390			$textdecoration = true;
1391		} else {
1392			$text = getBare(html_encode($archive));
1393			$textdecoration = false;
1394		}
1395		echo "<a href=\"" . html_encode(getCustomPageURL('archive', NULL)) . "\"$class title=\"" . $text . "\">";
1396		printf('%s' . $text . '%s', $textdecoration ? '<em>' : '', $textdecoration ? '</em>' : '');
1397		echo "</a>";
1398		echo '<span class="betweentext">' . html_encode($between) . '</span>';
1399		if ($format) {
1400			$d = strtotime($d);
1401			$d = strftime($format, $d);
1402		}
1403		echo $d;
1404	} else {
1405		if (is_null($search)) {
1406			$text = gettext('Search');
1407			$textdecoration = true;
1408		} else {
1409			$text = getBare(html_encode($search));
1410			$textdecoration = false;
1411		}
1412		printf('%s' . $text . '%s', $textdecoration ? '<em>' : '', $textdecoration ? '</em>' : '');
1413	}
1414}
1415
1416/**
1417 * returns the breadcrumb navigation for album, gallery and image view.
1418 *
1419 * @return array
1420 */
1421function getParentBreadcrumb() {
1422	global $_zp_gallery, $_zp_current_search, $_zp_current_album, $_zp_last_album;
1423	$output = array();
1424	if (in_context(ZP_SEARCH_LINKED)) {
1425		$page = $_zp_current_search->page;
1426		$searchwords = $_zp_current_search->getSearchWords();
1427		$searchdate = $_zp_current_search->getSearchDate();
1428		$searchfields = $_zp_current_search->getSearchFields(true);
1429		$search_album_list = $_zp_current_search->getAlbumList();
1430		if (!is_array($search_album_list)) {
1431			$search_album_list = array();
1432		}
1433		$searchpagepath = getSearchURL($searchwords, $searchdate, $searchfields, $page, array('albums' => $search_album_list));
1434		$dynamic_album = $_zp_current_search->getDynamicAlbum();
1435		if (empty($dynamic_album)) {
1436			if (empty($searchdate)) {
1437				$output[] = array('link' => $searchpagepath, 'title' => gettext("Return to search"), 'text' => gettext("Search"));
1438				if (is_null($_zp_current_album)) {
1439					return $output;
1440				} else {
1441					$parents = getParentAlbums();
1442				}
1443			} else {
1444				return array(array('link' => $searchpagepath, 'title' => gettext("Return to archive"), 'text' => gettext("Archive")));
1445			}
1446		} else {
1447			$album = $dynamic_album;
1448			$parents = getParentAlbums($album);
1449			if (in_context(ZP_ALBUM_LINKED)) {
1450				array_push($parents, $album);
1451			}
1452		}
1453// remove parent links that are not in the search path
1454		foreach ($parents as $key => $analbum) {
1455			$target = $analbum->name;
1456			if ($target !== $dynamic_album && !in_array($target, $search_album_list)) {
1457				unset($parents[$key]);
1458			}
1459		}
1460	} else {
1461		$parents = getParentAlbums();
1462	}
1463	$n = count($parents);
1464	if ($n > 0) {
1465		array_push($parents, $_zp_current_album);
1466		$index = -1;
1467		foreach ($parents as $parent) {
1468			$index++;
1469			if($index != 0) {
1470				$parentparent = $parents[$index-1];
1471				$page = $parent->getGalleryPage();
1472				$url = $parentparent->getLink($page);
1473				$output[] = array('link' => html_encode($url), 'title' => $parentparent->getTitle(), 'text' => $parentparent->getTitle());
1474			}
1475		}
1476	}
1477	return $output;
1478}
1479
1480/**
1481 * Prints the breadcrumb navigation for album, gallery and image view.
1482 *
1483 * @param string $before Insert here the text to be printed before the links
1484 * @param string $between Insert here the text to be printed between the links
1485 * @param string $after Insert here the text to be printed after the links
1486 * @param mixed $truncate if not empty, the max lenght of the description.
1487 * @param string $elipsis the text to append to the truncated description
1488 */
1489function printParentBreadcrumb($before = NULL, $between = NULL, $after = NULL, $truncate = NULL, $elipsis = NULL) {
1490	$crumbs = getParentBreadcrumb();
1491	if (!empty($crumbs)) {
1492		if (is_null($between)) {
1493			$between = ' | ';
1494		}
1495		if (is_null($after)) {
1496			$after = ' | ';
1497		}
1498		if (is_null($elipsis)) {
1499			$elipsis = '...';
1500		}
1501		if ($before) {
1502			$output = '<span class="beforetext">' . html_encode($before) . '</span>';
1503		} else {
1504			$output = '';
1505		}
1506		if ($between) {
1507			$between = '<span class="betweentext">' . html_encode($between) . '</span>';
1508		}
1509		$i = 0;
1510		foreach ($crumbs as $crumb) {
1511			if ($i > 0) {
1512				$output .= $between;
1513			}
1514//cleanup things in description for use as attribute tag
1515			$desc = $crumb['title'];
1516			if (!empty($desc) && $truncate) {
1517				$desc = truncate_string($desc, $truncate, $elipsis);
1518			}
1519			$output .= '<a href="' . html_encode($crumb['link']) . '"' . ' title="' . html_encode(getBare($desc)) . '">' . html_encode($crumb['text']) . '</a>';
1520			$i++;
1521		}
1522		if ($after) {
1523			$output .= '<span class="aftertext">' . html_encode($after) . '</span>';
1524		}
1525		echo $output;
1526	}
1527}
1528
1529/**
1530 * Prints a link to the 'main website', not the Zenphoto site home page!
1531 * Only prints the link if the url is not empty and does not point back the gallery page
1532 *
1533 * @param string $before text to precede the link
1534 * @param string $after text to follow the link
1535 * @param string $title Title text
1536 * @param string $class optional css class
1537 * @param string $id optional css id
1538 *  */
1539function printHomeLink($before = '', $after = '', $title = NULL, $class = NULL, $id = NULL) {
1540	global $_zp_gallery;
1541	$site = rtrim($_zp_gallery->getWebsiteURL(), '/');
1542	if (!empty($site)) {
1543		$name = $_zp_gallery->getWebsiteTitle();
1544		if (empty($name)) {
1545			$name = gettext('Home');
1546		}
1547		if ($site != SEO_FULLWEBPATH) {
1548			if ($before) {
1549				echo '<span class="beforetext">' . html_encode($before) . '</span>';
1550			}
1551			printLinkHTML($site, $name, $title, $class, $id);
1552			if ($after) {
1553				echo '<span class="aftertext">' . html_encode($after) . '</span>';
1554			}
1555		}
1556	}
1557}
1558
1559/**
1560 * Returns the formatted date field of the album
1561 *
1562 * @param string $format optional format string for the date
1563 * @return string
1564 */
1565function getAlbumDate($format = null) {
1566	global $_zp_current_album;
1567	$d = $_zp_current_album->getDateTime();
1568	if (empty($d) || ($d == '0000-00-00 00:00:00')) {
1569		return false;
1570	}
1571	if (is_null($format)) {
1572		return $d;
1573	}
1574	return zpFormattedDate($format, strtotime($d));
1575}
1576
1577/**
1578 * Prints the date of the current album
1579 *
1580 * @param string $before Insert here the text to be printed before the date.
1581 * @param string $format Format string for the date formatting
1582 */
1583function printAlbumDate($before = '', $format = NULL) {
1584	global $_zp_current_album;
1585	if (is_null($format)) {
1586		$format = DATE_FORMAT;
1587	}
1588	$date = getAlbumDate($format);
1589	if ($date) {
1590		if ($before) {
1591			$date = '<span class="beforetext">' . $before . '</span>' . $date;
1592		}
1593	}
1594	echo html_encodeTagged($date);
1595}
1596
1597/**
1598 * Returns the Location of the album.
1599 *
1600 * @return string
1601 */
1602function getAlbumLocation() {
1603	global $_zp_current_album;
1604	return $_zp_current_album->getLocation();
1605}
1606
1607/**
1608 * Prints the location of the album
1609 *
1610 * @author Ozh
1611 */
1612function printAlbumLocation() {
1613	echo html_encodeTagged(getAlbumLocation());
1614}
1615
1616/**
1617 * Returns the raw description of the current album.
1618 *
1619 * @return string
1620 */
1621function getAlbumDesc() {
1622	if (!in_context(ZP_ALBUM))
1623		return false;
1624	global $_zp_current_album;
1625	return $_zp_current_album->getDesc();
1626}
1627
1628/**
1629 * Returns a text-only description of the current album.
1630 *
1631 * @return string
1632 */
1633function getBareAlbumDesc() {
1634	return getBare(getAlbumDesc());
1635}
1636
1637/**
1638 * Prints description of the current album
1639 *
1640 * @author Ozh
1641 */
1642function printAlbumDesc() {
1643	global $_zp_current_album;
1644	echo html_encodeTagged(getAlbumDesc());
1645}
1646
1647function printBareAlbumDesc() {
1648	echo html_encode(getBareAlbumDesc());
1649}
1650
1651/**
1652 * Returns the custom_data field of the current album
1653 *
1654 * @return string
1655 */
1656function getAlbumCustomData() {
1657	global $_zp_current_album;
1658	return $_zp_current_album->getCustomData();
1659}
1660
1661/**
1662 * Prints the custom_data field of the current album.
1663 * Converts and displays line break in the admin field as <br />.
1664 *
1665 * @author Ozh
1666 */
1667function printAlbumCustomData() {
1668	echo html_encodeTagged(getAlbumCustomData());
1669}
1670
1671/**
1672 * A composit for getting album data
1673 *
1674 * @param string $field which field you want
1675 * @return string
1676 */
1677function getAlbumData($field) {
1678	if (!in_context(ZP_IMAGE))
1679		return false;
1680	global $_zp_album_image;
1681	return get_language_string($_zp_album_image->get($field));
1682}
1683
1684/**
1685 * Prints arbitrary data from the album object
1686 *
1687 * @param string $field the field name of the data desired
1688 * @param string $label text to label the field
1689 * @author Ozh
1690 */
1691function printAlbumData($field, $label = '') {
1692	global $_zp_current_album;
1693	echo html_encodeTagged($_zp_current_album->get($field));
1694}
1695
1696/**
1697 * Returns the album page number of the current image
1698 *
1699 * @param object $album optional album object
1700 * @return integer
1701 */
1702function getAlbumPage($album = NULL) {
1703	global $_zp_current_album, $_zp_current_image, $_zp_current_search, $_firstPageImages;
1704	if (is_null($album)) {
1705		$album = $_zp_current_album;
1706	}
1707	$use_realalbum = false;
1708	if (!$album->isDynamic()) {
1709		$use_realalbum = true;
1710	}
1711	$page = 0;
1712	if (in_context(ZP_IMAGE) && !in_context(ZP_SEARCH)) {
1713		$imageindex = $_zp_current_image->getIndex($use_realalbum);
1714		$numalbums = $album->getNumAlbums();
1715		$imagepage = floor(($imageindex - $_firstPageImages) / max(1, getOption('images_per_page'))) + 1;
1716		$albumpages = ceil($numalbums / max(1, getOption('albums_per_page')));
1717		if ($albumpages == 0 && $_firstPageImages > 0) {
1718			$imagepage++;
1719		}
1720		$page = $albumpages + $imagepage;
1721	}
1722	return $page;
1723}
1724
1725/**
1726 * Returns the album link url of the current album.
1727 *
1728 * @param object $album optional album object
1729 * @return string
1730 */
1731function getAlbumURL($album = NULL) {
1732	global $_zp_current_album;
1733	if (is_null($album))
1734		$album = $_zp_current_album;
1735	if (in_context(ZP_IMAGE)) {
1736		$page = getAlbumPage($album);
1737		if ($page <= 1)
1738			$page = 0;
1739	} else {
1740		$page = 0;
1741	}
1742	return $album->getLink($page);
1743}
1744
1745/**
1746 * Prints the album link url of the current album.
1747 *
1748 * @param string $text Insert the link text here.
1749 * @param string $title Insert the title text here.
1750 * @param string $class Insert here the CSS-class name with with you want to style the link.
1751 * @param string $id Insert here the CSS-id name with with you want to style the link.
1752 */
1753function printAlbumURL($text, $title, $class = NULL, $id = NULL) {
1754	printLinkHTML(getAlbumURL(), $text, $title, $class, $id);
1755}
1756
1757/**
1758 * Returns the name of the defined album thumbnail image.
1759 *
1760 * @return string
1761 */
1762function getAlbumThumb() {
1763	global $_zp_current_album;
1764	return $_zp_current_album->getThumb();
1765}
1766
1767/**
1768 * Returns an img src link to the password protect thumb substitute
1769 *
1770 * @param string $extra extra stuff to put in the HTML
1771 * @return string
1772 */
1773function getPasswordProtectImage($extra = '') {
1774	global $_zp_themeroot;
1775	$image = '';
1776	$themedir = SERVERPATH . '/themes/' . basename($_zp_themeroot);
1777	if (file_exists(internalToFilesystem($themedir . '/images/err-passwordprotected.png'))) {
1778		$image = $_zp_themeroot . '/images/err-passwordprotected.png';
1779	} else if (file_exists(internalToFilesystem($themedir . '/images/err-passwordprotected.gif'))) {
1780		$image = $_zp_themeroot . '/images/err-passwordprotected.gif';
1781	} else {
1782		$image = WEBPATH . '/' . ZENFOLDER . '/images/err-passwordprotected.png';
1783	}
1784	return '<img src="' . $image . '" ' . $extra . ' alt="protected" loading="lazy" />';
1785}
1786
1787/**
1788 * Prints the album thumbnail image.
1789 *
1790 * @param string $alt Insert the text for the alternate image name here.
1791 * @param string $class Insert here the CSS-class name with with you want to style the link.
1792 * @param string $id Insert here the CSS-id name with with you want to style the link.
1793 * @param string $title option title attribute
1794 *  */
1795function printAlbumThumbImage($alt, $class = NULL, $id = NULL , $title = null) {
1796	global $_zp_current_album;
1797	$thumbobj = $_zp_current_album->getAlbumThumbImage();
1798	$sizes = getSizeDefaultThumb($thumbobj);
1799	if (empty($title)) {
1800		$title = $alt;
1801	}
1802	$attr = array(
1803			'src' => html_pathurlencode($thumbobj->getThumb('album')),
1804			'alt' => html_encode($alt),
1805			'title' => html_encode($title),
1806			'class' => $class,
1807			'id' => $id,
1808			'width' => $sizes[0],
1809			'height' => $sizes[1],
1810			'loading' => 'lazy'
1811	);
1812	if (!$_zp_current_album->isPublished()) {
1813		$attr['class'] .= " not_visible";
1814	}
1815	$pwd = $_zp_current_album->getPassword();
1816	if (!empty($pwd)) {
1817		$attr['class'] .= " password_protected";
1818	}
1819	$attr['class'] = trim($attr['class']);
1820	$attr_filtered = zp_apply_filter('standard_album_thumb_attr', $attr, $thumbobj);
1821	if (!getOption('use_lock_image') || $_zp_current_album->isMyItem(LIST_RIGHTS) || empty($pwd)) {
1822		$attributes = generateAttributesFromArray($attr_filtered);
1823		$html = '<img' . $attributes . ' />';
1824		$html = zp_apply_filter('standard_album_thumb_html', $html, $thumbobj);
1825		echo $html;
1826	} else {
1827		$size = ' width="' . $attr['width'] . '"';
1828		echo getPasswordProtectImage($size);
1829	}
1830}
1831
1832/**
1833 * Returns a link to a custom sized thumbnail of the current album
1834 *
1835 * @param int $size the size of the image to have
1836 * @param int $width width
1837 * @param int $height height
1838 * @param int $cropw crop width
1839 * @param int $croph crop height
1840 * @param int $cropx crop part x axis
1841 * @param int $cropy crop part y axis
1842 * @param bool $effects image effects (e.g. set 'gray' to force grayscale)
1843 *
1844 * @return string
1845 */
1846function getCustomAlbumThumb($size, $width = NULL, $height = NULL, $cropw = NULL, $croph = NULL, $cropx = NULL, $cropy = null, $effects = NULL) {
1847	global $_zp_current_album;
1848	$thumb = $_zp_current_album->getAlbumThumbImage();
1849	return $thumb->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, true, $effects);
1850}
1851
1852/**
1853 * Prints a link to a custom sized thumbnail of the current album
1854 *
1855 * See getCustomImageURL() for details.
1856 *
1857 * @param string $alt Alt atribute text
1858 * @param int $size size
1859 * @param int $width width
1860 * @param int $height height
1861 * @param int $cropw cropwidth
1862 * @param int $croph crop height
1863 * @param int $cropx crop part x axis
1864 * @param int $cropy crop part y axis
1865 * @param string $class css class
1866 * @param string $id css id
1867 * @param string $title title attribute
1868 * @param bool $maxspace true for maxspace image, false is default
1869 *
1870 * @return string
1871 */
1872function printCustomAlbumThumbImage($alt, $size, $width = NULL, $height = NULL, $cropw = NULL, $croph = NULL, $cropx = NULL, $cropy = null, $class = NULL, $id = NULL, $title = null, $maxspace = false) {
1873	global $_zp_current_album;
1874	$thumbobj = $_zp_current_album->getAlbumThumbImage();
1875	$sizes = getSizeCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $thumbobj, 'thumb');
1876	if (empty($title)) {
1877		$title = $alt;
1878	}
1879	$attr = array(
1880			'alt' => html_encode($alt),
1881			'class' => $class,
1882			'title' => html_encode($title),
1883			'id' => $id,
1884			'loading' => 'lazy'
1885	);
1886	if ($maxspace) {
1887		getMaxSpaceContainer($width, $height, $thumbobj, true);
1888		$attr['width'] = $width;
1889		$attr['height'] = $height;
1890	} else {
1891		$attr['width'] = $sizes[0];
1892		$attr['height'] = $sizes[1];
1893	}
1894	if (!$_zp_current_album->isPublished()) {
1895		$attr['class'] .= " not_visible";
1896	}
1897	$pwd = $_zp_current_album->getPassword();
1898	if (!empty($pwd)) {
1899		$attr['class'] .= " password_protected";
1900	}
1901	$attr['class'] = trim($attr['class']);
1902	if ($maxspace) {
1903		$attr['src']= html_pathurlencode(getCustomAlbumThumb(null, $width, $height, null, null, null, null));
1904	} else {
1905		$attr['src']= html_pathurlencode(getCustomAlbumThumb($size, $width, $height, $cropw, $croph, $cropx, $cropy));
1906	}
1907	$attr_filtered = zp_apply_filter('custom_album_thumb_attr', $attr, $thumbobj);
1908	if (!getOption('use_lock_image') || $_zp_current_album->isMyItem(LIST_RIGHTS) || empty($pwd)) {
1909		$attributes = generateAttributesFromArray($attr_filtered);
1910		$html = '<img' . $attributes . ' />';
1911		$html = zp_apply_filter('custom_album_thumb_html', $html, $thumbobj);
1912		echo $html;
1913	} else {
1914		$size = ' width="' . $attr['width'] . '"';
1915		echo getPasswordProtectImage($size);
1916	}
1917}
1918
1919/**
1920 * Called by ***MaxSpace functions to compute the parameters to be passed to xxCustomyyy functions.
1921 *
1922 * @param int $width maxspace width
1923 * @param int $height maxspace height
1924 * @param object $image the image in question
1925 * @param bool $thumb true if for a thumbnail
1926 */
1927function getMaxSpaceContainer(&$width, &$height, $image, $thumb = false) {
1928	global $_zp_gallery;
1929	$upscale = getOption('image_allow_upscale');
1930	$imagename = $image->filename;
1931	if ($thumb) {
1932		$s_width = $image->getThumbWidth();
1933		$s_height = $image->getThumbHeight();
1934	} else {
1935		$s_width = $image->get('width');
1936		if ($s_width == 0)
1937			$s_width = max($width, $height);
1938		$s_height = $image->get('height');
1939		if ($s_height == 0)
1940			$s_height = max($width, $height);
1941	}
1942
1943	$newW = round($height / $s_height * $s_width);
1944	$newH = round($width / $s_width * $s_height);
1945	if (DEBUG_IMAGE)
1946		debugLog("getMaxSpaceContainer($width, $height, $imagename, $thumb): \$s_width=$s_width; \$s_height=$s_height; \$newW=$newW; \$newH=$newH; \$upscale=$upscale;");
1947	if ($newW > $width) {
1948		if ($upscale || $s_height > $newH) {
1949			$height = $newH;
1950		} else {
1951			$height = $s_height;
1952			$width = $s_width;
1953		}
1954	} else {
1955		if ($upscale || $s_width > $newW) {
1956			$width = $newW;
1957		} else {
1958			$height = $s_height;
1959			$width = $s_width;
1960		}
1961	}
1962}
1963
1964/**
1965 * Returns a link to a un-cropped custom sized version of the current album thumb within the given height and width dimensions.
1966 *
1967 * @param int $width width
1968 * @param int $height height
1969 * @return string
1970 */
1971function getCustomAlbumThumbMaxSpace($width, $height) {
1972	global $_zp_current_album;
1973	$albumthumb = $_zp_current_album->getAlbumThumbImage();
1974	getMaxSpaceContainer($width, $height, $albumthumb, true);
1975	return getCustomAlbumThumb(NULL, $width, $height, NULL, NULL, NULL, NULL);
1976}
1977
1978/**
1979 * Prints a un-cropped custom sized album thumb within the given height and width dimensions.
1980 * Note: a class of 'not_visible' or 'password_protected' will be added as appropriate
1981 *
1982 * @param string $alt Alt text for the url
1983 * @param int $width width
1984 * @param int $height height
1985 * @param string $class Optional style class
1986 * @param string $id Optional style id
1987 * @param string $title Optional title attribute
1988 */
1989function printCustomAlbumThumbMaxSpace($alt, $width, $height, $class = NULL, $id = NULL, $title = null) {
1990	printCustomAlbumThumbImage($alt, NULL, $width, $height, NULL, NULL, NULL, NULL, $class, $id, $title, true);
1991}
1992
1993/**
1994 * Returns the next album
1995 *
1996 * @return object
1997 */
1998function getNextAlbum() {
1999	global $_zp_current_album, $_zp_current_search, $_zp_gallery;
2000	if (in_context(ZP_SEARCH) || in_context(ZP_SEARCH_LINKED)) {
2001		$nextalbum = $_zp_current_search->getNextAlbum($_zp_current_album->name);
2002	} else if (in_context(ZP_ALBUM)) {
2003		$nextalbum = $_zp_current_album->getNextAlbum();
2004	} else {
2005		return null;
2006	}
2007	return $nextalbum;
2008}
2009
2010/**
2011 * Get the URL of the next album in the gallery.
2012 *
2013 * @return string
2014 */
2015function getNextAlbumURL() {
2016	$nextalbum = getNextAlbum();
2017	if ($nextalbum) {
2018		return $nextalbum->getLink();
2019	}
2020	return false;
2021}
2022
2023/**
2024 * Returns the previous album
2025 *
2026 * @return object
2027 */
2028function getPrevAlbum() {
2029	global $_zp_current_album, $_zp_current_search;
2030	if (in_context(ZP_SEARCH) || in_context(ZP_SEARCH_LINKED)) {
2031		$prevalbum = $_zp_current_search->getPrevAlbum($_zp_current_album->name);
2032	} else if (in_context(ZP_ALBUM)) {
2033		$prevalbum = $_zp_current_album->getPrevAlbum();
2034	} else {
2035		return null;
2036	}
2037	return $prevalbum;
2038}
2039
2040/**
2041 * Get the URL of the previous album in the gallery.
2042 *
2043 * @return string
2044 */
2045function getPrevAlbumURL() {
2046	$prevalbum = getPrevAlbum();
2047	if ($prevalbum) {
2048		return $prevalbum->getLink();
2049	}
2050	return false;
2051}
2052
2053/**
2054 * Returns true if this page has image thumbs on it
2055 *
2056 * @return bool
2057 */
2058function isImagePage() {
2059	if (getNumImages()) {
2060		global $_zp_page, $_firstPageImages;
2061		$imagestart = getTotalPages(2); // # of album pages
2062		if (!$_firstPageImages)
2063			$imagestart++; // then images start on the last album page.
2064		return $_zp_page >= $imagestart;
2065	}
2066	return false;
2067}
2068
2069/**
2070 * Returns true if this page has album thumbs on it
2071 *
2072 * @return bool
2073 */
2074function isAlbumPage() {
2075	global $_zp_page;
2076	$pageCount = Ceil(getNumAlbums() / max(1, getOption('albums_per_page')));
2077	return ($_zp_page <= $pageCount);
2078}
2079
2080/**
2081 * Returns the number of images in the album.
2082 *
2083 * @return int
2084 */
2085function getNumImages() {
2086	global $_zp_current_album, $_zp_current_search;
2087	if ((in_context(ZP_SEARCH_LINKED) && !in_context(ZP_ALBUM_LINKED)) || in_context(ZP_SEARCH) && is_null($_zp_current_album)) {
2088		return $_zp_current_search->getNumImages();
2089	} else {
2090		return $_zp_current_album->getNumImages();
2091	}
2092}
2093
2094/**
2095 * Returns the next image on a page.
2096 * sets $_zp_current_image to the next image in the album.
2097
2098 * Returns true if there is an image to be shown
2099 *
2100 * @param bool $all set to true disable pagination
2101 * @param int $firstPageCount the number of images which can go on the page that transitions between albums and images
2102 * 							Normally this parameter should be NULL so as to use the default computations.
2103 * @param bool $mine overridePassword the password check
2104 * @return bool
2105 *
2106 * @return bool
2107 */
2108function next_image($all = false, $firstPageCount = NULL, $mine = NULL) {
2109	global $_zp_images, $_zp_current_image, $_zp_current_album, $_zp_page, $_zp_current_image_restore, $_zp_current_search, $_zp_gallery, $_firstPageImages;
2110	if (is_null($firstPageCount)) {
2111		$firstPageCount = $_firstPageImages;
2112	}
2113	$imagePageOffset = getTotalPages(2); /* gives us the count of pages for album thumbs */
2114	if ($all) {
2115		$imagePage = 1;
2116		$firstPageCount = 0;
2117	} else {
2118		$_firstPageImages = $firstPageCount; /* save this so pagination can see it */
2119		$imagePage = $_zp_page - $imagePageOffset;
2120	}
2121	if ($firstPageCount > 0 && $imagePageOffset > 0) {
2122		$imagePage = $imagePage + 1; /* can share with last album page */
2123	}
2124	if ($imagePage <= 0) {
2125		return false; /* we are on an album page */
2126	}
2127	if (is_null($_zp_images)) {
2128		if (in_context(ZP_SEARCH)) {
2129			$_zp_images = $_zp_current_search->getImages($all ? 0 : ($imagePage), $firstPageCount, NULL, NULL, true, $mine);
2130		} else {
2131			$_zp_images = $_zp_current_album->getImages($all ? 0 : ($imagePage), $firstPageCount, NULL, NULL, true, $mine);
2132		}
2133		if (empty($_zp_images)) {
2134			return NULL;
2135		}
2136		$_zp_current_image_restore = $_zp_current_image;
2137		$img = array_shift($_zp_images);
2138		$_zp_current_image = newImage($_zp_current_album, $img, true, true);
2139		save_context();
2140		add_context(ZP_IMAGE);
2141		return true;
2142	} else if (empty($_zp_images)) {
2143		$_zp_images = NULL;
2144		$_zp_current_image = $_zp_current_image_restore;
2145		restore_context();
2146		return false;
2147	} else {
2148		$img = array_shift($_zp_images);
2149		$_zp_current_image = newImage($_zp_current_album, $img, true, true);
2150		return true;
2151	}
2152}
2153
2154//*** Image Context ************************
2155//******************************************
2156
2157/**
2158 * Sets the image passed as the current image
2159 *
2160 * @param object $image the image to become current
2161 */
2162function makeImageCurrent($image) {
2163	if (!is_object($image))
2164		return;
2165	global $_zp_current_album, $_zp_current_image;
2166	$_zp_current_image = $image;
2167	$_zp_current_album = $_zp_current_image->getAlbum();
2168	set_context(ZP_INDEX | ZP_ALBUM | ZP_IMAGE);
2169}
2170
2171/**
2172 * Returns the raw title of the current image.
2173 *
2174 * @return string
2175 */
2176function getImageTitle() {
2177	if (!in_context(ZP_IMAGE))
2178		return false;
2179	global $_zp_current_image;
2180	return $_zp_current_image->getTitle();
2181}
2182
2183/**
2184 * Returns a text-only title of the current image.
2185 *
2186 * @return string
2187 */
2188function getBareImageTitle() {
2189	return getBare(getImageTitle());
2190}
2191
2192/**
2193 * Returns the image title taged with not visible annotation.
2194 *
2195 * @return string
2196 */
2197function getAnnotatedImageTitle() {
2198	global $_zp_current_image;
2199	$title = getBareImageTitle();
2200	if (!$_zp_current_image->isPublished()) {
2201		$title .= "\n" . gettext('The image is marked un-published.');
2202	}
2203	return $title;
2204}
2205
2206function printAnnotatedImageTitle() {
2207	echo html_encode(getAnnotatedImageTitle());
2208}
2209
2210/**
2211 * Prints title of the current image
2212 *
2213 * @author Ozh
2214 */
2215function printImageTitle() {
2216	echo html_encodeTagged(getImageTitle());
2217}
2218
2219function printBareImageTitle() {
2220	echo html_encode(getBareImageTitle());
2221}
2222
2223/**
2224 * Returns the 'n' of n of m images
2225 *
2226 * @return int
2227 */
2228function imageNumber() {
2229	global $_zp_current_image, $_zp_current_search, $_zp_current_album;
2230	$name = $_zp_current_image->getFileName();
2231	if (in_context(ZP_SEARCH) || (in_context(ZP_SEARCH_LINKED) && !in_context(ZP_ALBUM_LINKED))) {
2232		$folder = $_zp_current_image->imagefolder;
2233		$images = $_zp_current_search->getImages();
2234		$c = 0;
2235		foreach ($images as $image) {
2236			$c++;
2237			if ($name == $image['filename'] && $folder == $image['folder']) {
2238				return $c;
2239			}
2240		}
2241	} else {
2242		return $_zp_current_image->getIndex() + 1;
2243	}
2244	return false;
2245}
2246
2247/**
2248 * Returns the image date of the current image in yyyy-mm-dd hh:mm:ss format.
2249 * Pass it a date format string for custom formatting
2250 *
2251 * @param string $format formatting string for the data
2252 * @return string
2253 */
2254function getImageDate($format = null) {
2255	if (!in_context(ZP_IMAGE))
2256		return false;
2257	global $_zp_current_image;
2258	$d = $_zp_current_image->getDateTime();
2259	if (empty($d) || ($d == '0000-00-00 00:00:00')) {
2260		return false;
2261	}
2262	if (is_null($format)) {
2263		return $d;
2264	}
2265	return zpFormattedDate($format, strtotime($d));
2266}
2267
2268/**
2269 * Prints the date of the current album
2270 *
2271 * @param string $before Insert here the text to be printed before the date.
2272 * @param string $format Format string for the date formatting
2273 */
2274function printImageDate($before = '', $format = null) {
2275	global $_zp_current_image;
2276	if (is_null($format)) {
2277		$format = DATE_FORMAT;
2278	}
2279	$date = getImageDate($format);
2280	if ($date) {
2281		if ($before) {
2282			$date = '<span class="beforetext">' . $before . '</span>' . $date;
2283		}
2284	}
2285	echo html_encodeTagged($date);
2286}
2287
2288// IPTC fields
2289/**
2290 * Returns the Location field of the current image
2291 *
2292 * @return string
2293 */
2294function getImageLocation() {
2295	if (!in_context(ZP_IMAGE))
2296		return false;
2297	global $_zp_current_image;
2298	return $_zp_current_image->getLocation();
2299}
2300
2301/**
2302 * Returns the City field of the current image
2303 *
2304 * @return string
2305 */
2306function getImageCity() {
2307	if (!in_context(ZP_IMAGE))
2308		return false;
2309	global $_zp_current_image;
2310	return $_zp_current_image->getcity();
2311}
2312
2313/**
2314 * Returns the State field of the current image
2315 *
2316 * @return string
2317 */
2318function getImageState() {
2319	if (!in_context(ZP_IMAGE))
2320		return false;
2321	global $_zp_current_image;
2322	return $_zp_current_image->getState();
2323}
2324
2325/**
2326 * Returns the Country field of the current image
2327 *
2328 * @return string
2329 */
2330function getImageCountry() {
2331	if (!in_context(ZP_IMAGE))
2332		return false;
2333	global $_zp_current_image;
2334	return $_zp_current_image->getCountry();
2335}
2336
2337/**
2338 * Returns the raw description of the current image.
2339 * new lines are replaced with <br /> tags
2340 *
2341 * @return string
2342 */
2343function getImageDesc() {
2344	if (!in_context(ZP_IMAGE))
2345		return false;
2346	global $_zp_current_image;
2347	return $_zp_current_image->getDesc();
2348}
2349
2350/**
2351 * Returns a text-only description of the current image.
2352 *
2353 * @return string
2354 */
2355function getBareImageDesc() {
2356	return getBare(getImageDesc());
2357}
2358
2359/**
2360 * Prints the description of the current image.
2361 * Converts and displays line breaks set in the admin field as <br />.
2362 *
2363 */
2364function printImageDesc() {
2365	echo html_encodeTagged(getImageDesc());
2366}
2367
2368function printBareImageDesc() {
2369	echo html_encode(getBareImageDesc());
2370}
2371
2372/**
2373 * A composit for getting image data
2374 *
2375 * @param string $field which field you want
2376 * @return string
2377 */
2378function getImageData($field) {
2379	if (!in_context(ZP_IMAGE))
2380		return false;
2381	global $_zp_current_image;
2382	return get_language_string($_zp_current_image->get($field));
2383}
2384
2385/**
2386 * Returns the custom_data field of the current image
2387 *
2388 * @return string
2389 */
2390function getImageCustomData() {
2391	Global $_zp_current_image;
2392	return $_zp_current_image->getCustomData();
2393}
2394
2395/**
2396 * Prints the custom_data field of the current image.
2397 * Converts and displays line breaks set in the admin field as <br />.
2398 *
2399 * @return string
2400 */
2401function printImageCustomData() {
2402	$data = getImageCustomData();
2403	$data = str_replace("\r\n", "\n", $data);
2404	$data = str_replace("\n", "<br />", $data);
2405	echo $data;
2406}
2407
2408/**
2409 * Prints arbitrary data from the image object
2410 *
2411 * @param string $field the field name of the data desired
2412 * @param string $label text to label the field.
2413 * @author Ozh
2414 */
2415function printImageData($field, $label = '') {
2416  global $_zp_current_image;
2417  $text = getImageData($field);
2418  if (!empty($text)) {
2419    echo html_encodeTagged($label . $text);
2420  }
2421}
2422
2423/**
2424 * Returns the file size of the full original image
2425 *
2426 * @since ZenphotoCMS 1.5.2
2427 *
2428 * @global obj $_zp_current_image
2429 * @return int
2430 */
2431function getFullImageFilesize() {
2432	global $_zp_current_image;
2433	$filesize = $_zp_current_image->getFilesize();
2434	if($filesize) {
2435		return byteConvert($filesize);
2436	}
2437}
2438
2439/**
2440 * True if there is a next image
2441 *
2442 * @return bool
2443 */
2444function hasNextImage() {
2445  global $_zp_current_image;
2446  if (is_null($_zp_current_image))
2447    return false;
2448  return $_zp_current_image->getNextImage();
2449}
2450
2451/**
2452 * True if there is a previous image
2453 *
2454 * @return bool
2455 */
2456function hasPrevImage() {
2457  global $_zp_current_image;
2458  if (is_null($_zp_current_image))
2459    return false;
2460  return $_zp_current_image->getPrevImage();
2461}
2462
2463/**
2464 * Returns the url of the next image.
2465 *
2466 * @return string
2467 */
2468function getNextImageURL() {
2469	if (!in_context(ZP_IMAGE))
2470		return false;
2471	global $_zp_current_album, $_zp_current_image;
2472	if (is_null($_zp_current_image))
2473		return false;
2474	$nextimg = $_zp_current_image->getNextImage();
2475	return $nextimg->getLink();
2476}
2477
2478/**
2479 * Returns the url of the previous image.
2480 *
2481 * @return string
2482 */
2483function getPrevImageURL() {
2484	if (!in_context(ZP_IMAGE))
2485		return false;
2486	global $_zp_current_album, $_zp_current_image;
2487	if (is_null($_zp_current_image))
2488		return false;
2489	$previmg = $_zp_current_image->getPrevImage();
2490	return $previmg->getLink();
2491}
2492
2493/**
2494 * Returns the thumbnail of the previous image.
2495 *
2496 * @return string
2497 */
2498function getPrevImageThumb() {
2499	if (!in_context(ZP_IMAGE))
2500		return false;
2501	global $_zp_current_image;
2502	if (is_null($_zp_current_image))
2503		return false;
2504	$img = $_zp_current_image->getPrevImage();
2505	return $img->getThumb();
2506}
2507
2508/**
2509 * Returns the thumbnail of the next image.
2510 *
2511 * @return string
2512 */
2513function getNextImageThumb() {
2514	if (!in_context(ZP_IMAGE))
2515		return false;
2516	global $_zp_current_image;
2517	if (is_null($_zp_current_image))
2518		return false;
2519	$img = $_zp_current_image->getNextImage();
2520	return $img->getThumb();
2521}
2522
2523/**
2524 * Returns the url of the current image.
2525 *
2526 * @return string
2527 */
2528function getImageURL() {
2529	if (!in_context(ZP_IMAGE))
2530		return false;
2531	global $_zp_current_image;
2532	if (is_null($_zp_current_image))
2533		return false;
2534	return $_zp_current_image->getLink();
2535}
2536
2537/**
2538 * Prints the link to the current  image.
2539 *
2540 * @param string $text text for the link
2541 * @param string $title title tag for the link
2542 * @param string $class optional style class for the link
2543 * @param string $id optional style id for the link
2544 */
2545function printImageURL($text, $title, $class = NULL, $id = NULL) {
2546	printLinkHTML(getImageURL(), $text, $title, $class, $id);
2547}
2548
2549/**
2550 * Returns the Metadata infromation from the current image
2551 *
2552 * @param $image optional image object
2553 * @param string $displayonly set to true to return only the items selected for display
2554 * @return array
2555 */
2556function getImageMetaData($image = NULL, $displayonly = true) {
2557	global $_zp_current_image, $_zp_exifvars;
2558	if (is_null($image))
2559		$image = $_zp_current_image;
2560	if (is_null($image) || !$image->get('hasMetadata')) {
2561		return false;
2562	}
2563	$data = $image->getMetaData();
2564	if ($displayonly) {
2565		foreach ($data as $field => $value) { //	remove the empty or not selected to display
2566			if (!$value || !$_zp_exifvars[$field][3]) {
2567				unset($data[$field]);
2568			}
2569		}
2570	}
2571	if (count($data) > 0) {
2572		return $data;
2573	}
2574	return false;
2575}
2576
2577/**
2578 * Prints the Metadata data of the current image
2579 *
2580 * @param string $title title tag for the class
2581 * @param bool $toggle set to true to get a javascript toggle on the display of the data
2582 * @param string $id style class id
2583 * @param string $class style class
2584 * @author Ozh
2585 */
2586function printImageMetadata($title = NULL, $toggle = true, $id = 'imagemetadata', $class = null, $span = NULL) {
2587	global $_zp_exifvars, $_zp_current_image;
2588	if (false === ($exif = getImageMetaData($_zp_current_image, true))) {
2589		return;
2590	}
2591	if (is_null($title)) {
2592		$title = gettext('Image Info');
2593	}
2594	if ($class) {
2595		$class = ' class="' . $class . '"';
2596	}
2597	if (!$span) {
2598		$span = 'exif_link';
2599	}
2600	$dataid = $id . '_data';
2601	if ($id) {
2602		$id = ' id="' . $id . '"';
2603	}
2604	$style = '';
2605	if ($toggle) {
2606	 if(zp_has_filter('theme_head', 'colorbox::css')) {
2607	 	$modal_class = ' colorbox';
2608	 	?>
2609	 	<script>
2610	 	// <!-- <![CDATA[
2611		$(document).ready(function () {
2612			$(".colorbox").colorbox({
2613				inline: true,
2614				href: "#imagemetadata",
2615				close: '<?php echo gettext("close"); ?>'
2616			});
2617		});
2618		// ]]> -->
2619		</script>
2620		<?php
2621	 } else {
2622		 $modal_class = '';
2623			// we only need this eventhanlder if there is no colorbox!
2624			?>
2625 			<script>
2626 			// <!-- <![CDATA[
2627			$(document).ready(function () {
2628 				$(".metadata_toggle").click(function(event) {
2629 					event.preventDefault(); $("#<?php echo $dataid; ?>").toggle();
2630 				});
2631			});
2632			// ]]> -->
2633 			</script>
2634 			<?php
2635		}
2636		$style = ' style="display:none"';
2637		?>
2638		<span id="<?php echo $span; ?>" class="metadata_title">
2639			<a href="#" class="metadata_toggle<?php echo $modal_class; ?>" title="<?php echo $title; ?>"><?php echo $title; ?></a>
2640		</span>
2641		<?php
2642	}
2643	?>
2644	<div id="<?php echo $dataid; ?>"<?php echo $style; ?>>
2645		<div<?php echo $id . $class; ?>>
2646			<table>
2647				<?php
2648				foreach ($exif as $field => $value) {
2649					$label = $_zp_exifvars[$field][2];
2650					echo "<tr><td class=\"label\">$label:</td><td class=\"value\">";
2651					switch ($_zp_exifvars[$field][6]) {
2652						case 'time':
2653							echo zpFormattedDate(DATE_FORMAT, strtotime($value));
2654							break;
2655						default:
2656							echo html_encode($value);
2657							break;
2658					}
2659					echo "</td></tr>\n";
2660				}
2661				?>
2662			</table>
2663		</div>
2664	</div>
2665	<?php
2666}
2667
2668/**
2669 * Returns an array with the height & width
2670 *
2671 * @param int $size size
2672 * @param int $width width
2673 * @param int $height height
2674 * @param int $cw crop width
2675 * @param int $ch crop height
2676 * @param int $cx crop x axis
2677 * @param int $cy crop y axis
2678 * @param obj $image The image object for which the size is desired. NULL means the current image
2679 * @param string $type "image" (sizedimage) (default), "thumb" (thumbnail) required for using option settings for uncropped images
2680 * @return array
2681 */
2682function getSizeCustomImage($size, $width = NULL, $height = NULL, $cw = NULL, $ch = NULL, $cx = NULL, $cy = NULL, $image = NULL, $type = 'image') {
2683  global $_zp_current_image;
2684  if (is_null($image))
2685    $image = $_zp_current_image;
2686  if (is_null($image))
2687    return false;
2688
2689  //if we set width/height we are cropping and those are the sizes already
2690  if (!is_null($width) && !is_null($height)) {
2691    return array($width, $height);
2692  }
2693	switch ($type) {
2694		case 'thumb':
2695			$h = $image->getThumbHeight();
2696			$w = $image->getThumbWidth();
2697			$thumb = true;
2698			$side = getOption('thumb_use_side');
2699			break;
2700		default:
2701		case 'image':
2702			$h = $image->getHeight();
2703			$w = $image->getWidth();
2704			$thumb = false;
2705			if (isImageVideo($image)) { // size is determined by the player
2706				return array($w, $h);
2707			}
2708			$side = getOption('image_use_side');
2709			break;
2710	}
2711	$us = getOption('image_allow_upscale');
2712  $args = getImageParameters(array($size, $width, $height, $cw, $ch, $cx, $cy, NULL, $thumb, NULL, $thumb, NULL, NULL, NULL), $image->album->name);
2713  @list($size, $width, $height, $cw, $ch, $cx, $cy, $quality, $thumb, $crop, $thumbstandin, $passedWM, $adminrequest, $effects) = $args;
2714  if (!empty($size)) {
2715    $dim = $size;
2716    $width = $height = false;
2717  } else if (!empty($width)) {
2718    $dim = $width;
2719    $size = $height = false;
2720  } else if (!empty($height)) {
2721    $dim = $height;
2722    $size = $width = false;
2723  } else {
2724    $dim = 1;
2725  }
2726
2727  if ($w == 0) {
2728    $hprop = 1;
2729  } else {
2730    $hprop = round(($h / $w) * $dim);
2731  }
2732  if ($h == 0) {
2733    $wprop = 1;
2734  } else {
2735    $wprop = round(($w / $h) * $dim);
2736  }
2737  if (($size && ($side == 'longest' && $h > $w) || ($side == 'height') || ($side == 'shortest' && $h < $w)) || $height) {
2738// Scale the height
2739    $newh = $dim;
2740    $neww = $wprop;
2741  } else {
2742// Scale the width
2743    $neww = $dim;
2744    $newh = $hprop;
2745  }
2746  if (!$us && $newh >= $h && $neww >= $w) {
2747    return array($w, $h);
2748  } else {
2749    if ($cw && $cw < $neww)
2750      $neww = $cw;
2751    if ($ch && $ch < $newh)
2752      $newh = $ch;
2753    if ($size && $ch && $cw) {
2754      $neww = $cw;
2755      $newh = $ch;
2756    }
2757    return array($neww, $newh);
2758  }
2759}
2760
2761/**
2762 * Returns an array [width, height] of the default-sized image.
2763 *
2764 * @param int $size override the 'image_zize' option
2765 * @param $image object the image for which the size is desired. NULL means the current image
2766 *
2767 * @return array
2768 */
2769function getSizeDefaultImage($size = NULL, $image = NULL) {
2770  if (is_null($size))
2771    $size = getOption('image_size');
2772  return getSizeCustomImage($size, NULL, NULL, NULL, NULL, NULL, NULL, $image);
2773}
2774
2775/**
2776 * Returns an array [width, height] of the original image.
2777 *
2778 * @param $image object the image for which the size is desired. NULL means the current image
2779 *
2780 * @return array
2781 */
2782function getSizeFullImage($image = NULL) {
2783	global $_zp_current_image;
2784	if (is_null($image))
2785		$image = $_zp_current_image;
2786	if (is_null($image))
2787		return false;
2788	return array($image->getWidth(), $image->getHeight());
2789}
2790
2791/**
2792 * The width of the default-sized image (in printDefaultSizedImage)
2793 *
2794 * @param $image object the image for which the size is desired. NULL means the current image
2795 *
2796 * @return int
2797 */
2798function getDefaultWidth($size = NULL, $image = NULL) {
2799	$size_a = getSizeDefaultImage($size, $image);
2800	return $size_a[0];
2801}
2802
2803/**
2804 * Returns the height of the default-sized image (in printDefaultSizedImage)
2805 *
2806 * @param $image object the image for which the size is desired. NULL means the current image
2807 *
2808 * @return int
2809 */
2810function getDefaultHeight($size = NULL, $image = NULL) {
2811	$size_a = getSizeDefaultImage($size, $image);
2812	return $size_a[1];
2813}
2814
2815/**
2816 * Returns the width of the original image
2817 *
2818 * @param $image object the image for which the size is desired. NULL means the current image
2819 *
2820 * @return int
2821 */
2822function getFullWidth($image = NULL) {
2823	global $_zp_current_image;
2824	if (is_null($image))
2825		$image = $_zp_current_image;
2826	if (is_null($image))
2827		return false;
2828	return $image->getWidth();
2829}
2830
2831/**
2832 * Returns the height of the original image
2833 *
2834 * @param $image object the image for which the size is desired. NULL means the current image
2835 *
2836 * @return int
2837 */
2838function getFullHeight($image = NULL) {
2839	global $_zp_current_image;
2840	if (is_null($image))
2841		$image = $_zp_current_image;
2842	if (is_null($image))
2843		return false;
2844	return $image->getHeight();
2845}
2846
2847/**
2848 * Returns true if the image is landscape-oriented (width is greater than height)
2849 * or - kept here for backwards compatibility - square (equal widht and height)
2850 *
2851 * @param $image object the image for which the size is desired. NULL means the current image
2852 *
2853 * @return bool
2854 */
2855function isLandscape($image = NULL) {
2856	global $_zp_current_image;
2857	if (is_null($image))
2858		$image = $_zp_current_image;
2859	if (is_null($image))
2860		return false;
2861	return ($image->isLandscape() || $image->isSquare());
2862}
2863
2864/**
2865 * Returns the url to the default sized image.
2866 *
2867 * @param $image object the image for which the size is desired. NULL means the current image
2868 *
2869 * @return string
2870 */
2871function getDefaultSizedImage($image = NULL) {
2872	global $_zp_current_image;
2873	if (is_null($image))
2874		$image = $_zp_current_image;
2875	if (is_null($image))
2876		return false;
2877	return $image->getSizedImage(getOption('image_size'));
2878}
2879
2880/**
2881 * Show video player with video loaded or display the image.
2882 *
2883 * @param string $alt Alt text
2884 * @param string $class Optional style class
2885 * @param string $id Optional style id
2886 * @param string $title Optional title attribute
2887 * @param obj $image optional image object, null means current image
2888 */
2889function printDefaultSizedImage($alt, $class = null, $id = null, $title = null, $image = null) {
2890	global $_zp_current_image;
2891	if (is_null($image)) {
2892		$image = $_zp_current_image;
2893	}
2894	if (is_null($image)) {
2895		return false;
2896	}
2897	if (empty($title)) {
2898		$title = $alt;
2899	}
2900	$attr = array(
2901			'alt' => html_encode($alt),
2902			'class' => $class,
2903			'title' => html_encode($title),
2904			'id' => $id,
2905			'loading' => 'lazy',
2906			'width' => getDefaultWidth(),
2907			'height' => getDefaultHeight()
2908	);
2909	if (!$image->isPublished()) {
2910		$attr['class'] .= " not_visible";
2911	}
2912	$album = $image->getAlbum();
2913	$pwd = $album->getPassword();
2914	if (!empty($pwd)) {
2915		$attr['class'] .= " password_protected";
2916	}
2917	if (isImagePhoto($image)) { //Print images
2918		$attr['src'] = html_pathurlencode(getDefaultSizedImage());
2919		$attr_filtered = zp_apply_filter('standard_image_attr', $attr, $image);
2920		$attributes = generateAttributesFromArray($attr_filtered);
2921		$html = '<img' . $attributes . ' />';
2922		$html = zp_apply_filter('standard_image_html', $html, $image);
2923		echo $html;
2924	} else { // better be a plugin class then
2925		echo $image->getContent();
2926	}
2927}
2928
2929/**
2930 * Returns the url to the thumbnail of the current image.
2931 *
2932 * @return string
2933 */
2934function getImageThumb() {
2935	global $_zp_current_image;
2936	if (is_null($_zp_current_image))
2937		return false;
2938	return $_zp_current_image->getThumb();
2939}
2940
2941/**
2942 * @param string $alt Alt text
2943 * @param string $class optional class attribute
2944 * @param string $id optional id attribute
2945 * @param string $title optional title attribute
2946 * @param obj $image optional image object, null means current image
2947 */
2948function printImageThumb($alt, $class = null, $id = null, $title = null, $image = null) {
2949	global $_zp_current_image;
2950	if (is_null($image)) {
2951		$image = $_zp_current_image;
2952	}
2953	if (is_null($image)) {
2954		return false;
2955	}
2956	if (empty($title)) {
2957		$title = $alt;
2958	}
2959	$attr = array(
2960			'alt' => html_encode($alt),
2961			'class' => $class,
2962			'title' => html_encode($title),
2963			'id' => $id,
2964			'loading' => 'lazy'
2965	);
2966	if (!$image->isPublished()) {
2967		$attr['class'] .= " not_visible";
2968	}
2969	$album = $image->getAlbum();
2970	$pwd = $album->getPassword();
2971	if (!empty($pwd)) {
2972		$attr['class'] .= " password_protected";
2973	}
2974	$attr['src'] = html_pathurlencode($image->getThumb());
2975	$sizes = getSizeDefaultThumb($image);
2976	$attr['width'] = $sizes[0];
2977	$attr['height'] = $sizes[1];
2978	$attr_filtered = zp_apply_filter('standard_image_thumb_attr', $attr, $image);
2979	$attributes = generateAttributesFromArray($attr_filtered);
2980	$html = '<img' . $attributes . ' />';
2981	$html = zp_apply_filter('standard_image_thumb_html', $html, $image);
2982	echo $html;
2983}
2984
2985/**
2986 * Gets the width and height of a default thumb for the <img> tag height/width
2987 * @global type $_zp_current_image
2988 * @param obj $image Image object, if NULL the current image is used
2989 * @return aray
2990 */
2991function getSizeDefaultThumb($image = NULL) {
2992	global $_zp_current_image;
2993	if (is_null($image)) {
2994		$image = $_zp_current_image;
2995	}
2996	$s = getOption('thumb_size');
2997	if (getOption('thumb_crop')) {
2998		$w = getOption('thumb_crop_width');
2999		$h = getOption('thumb_crop_height');
3000		$sizes = getSizeCustomImage($s, $w, $h, $w, $h, null, null, $image, 'thumb');
3001	} else {
3002		$w = $h = $s;
3003		$sizes = getSizeCustomImage($s, NULL, NULL, NULL, NULL, NULL, NULL, $image, 'thumb');
3004	}
3005	return $sizes;
3006}
3007
3008/**
3009 * Returns the url to original image.
3010 * It will return a protected image is the option "protect_full_image" is set
3011 *
3012 * @param $image optional image object
3013 * @return string
3014 */
3015function getFullImageURL($image = NULL) {
3016	global $_zp_current_image;
3017	if (is_null($image)) {
3018		$image = $_zp_current_image;
3019	}
3020	if (is_null($image)) {
3021		return false;
3022	}
3023	$outcome = getOption('protect_full_image');
3024	if ($outcome == 'no-access') {
3025		return NULL;
3026	}
3027	if ($outcome == 'unprotected') {
3028		return $image->getFullImageURL();
3029	} else {
3030		return getProtectedImageURL($image, $outcome);
3031	}
3032}
3033
3034/**
3035 * Returns the "raw" url to the image in the albums folder
3036 *
3037 * @param $image optional image object
3038 * @return string
3039 *
3040 */
3041function getUnprotectedImageURL($image = NULL) {
3042	global $_zp_current_image;
3043	if (is_null($image)) {
3044		$image = $_zp_current_image;
3045	}
3046	if (!is_null($image)) {
3047		return $image->getFullImageURL();
3048	}
3049}
3050
3051/**
3052 * Returns an url to the password protected/watermarked current image
3053 *
3054 * @param object $image optional image object overrides the current image
3055 * @param string $disposal set to override the 'protect_full_image' option. 'protected', "download", "unprotected" or "no-access"
3056 * @return string
3057 * */
3058function getProtectedImageURL($image = NULL, $disposal = NULL) {
3059	global $_zp_current_image;
3060	if (is_null($disposal)) {
3061		$disposal = getOption('protect_full_image');
3062	}
3063	if ($disposal == 'no-access')
3064		return NULL;
3065	if (is_null($image)) {
3066		if (!in_context(ZP_IMAGE))
3067			return false;
3068		if (is_null($_zp_current_image))
3069			return false;
3070		$image = $_zp_current_image;
3071	}
3072	$album = $image->getAlbum();
3073	$watermark_use_image = getWatermarkParam($image, WATERMARK_FULL);
3074	if (!empty($watermark_use_image)) {
3075		$wmt = $watermark_use_image;
3076	} else {
3077		$wmt = false;
3078	}
3079	$args = array('FULL', NULL, NULL, NULL, NULL, NULL, NULL, (int) getOption('full_image_quality'), NULL, NULL, NULL, $wmt, false, NULL, NULL);
3080	$cache_file = getImageCacheFilename($album->name, $image->filename, $args);
3081	$cache_path = SERVERCACHE . $cache_file;
3082	if ($disposal != 'download' && OPEN_IMAGE_CACHE && file_exists($cache_path)) {
3083		return WEBPATH . '/' . CACHEFOLDER . pathurlencode(imgSrcURI($cache_file));
3084	} else if ($disposal == 'unprotected') {
3085		return getImageURI($args, $album->name, $image->filename, $image->filemtime);
3086	} else {
3087		$params = '&q=' . getOption('full_image_quality');
3088		if (!empty($watermark_use_image)) {
3089			$params .= '&wmk=' . $watermark_use_image;
3090		}
3091		if ($disposal) {
3092			$params .= '&dsp=' . $disposal;
3093		}
3094		$params .= '&check=' . sha1(HASH_SEED . serialize($args));
3095		if (is_array($image->filename)) {
3096			$album = dirname($image->filename['source']);
3097			$image = basename($image->filename['source']);
3098		} else {
3099			$album = $album->name;
3100			$image = $image->filename;
3101		}
3102		return WEBPATH . '/' . ZENFOLDER . '/full-image.php?a=' . $album . '&i=' . $image . $params;
3103	}
3104}
3105
3106/**
3107 * Returns a link to the current image custom sized to $size
3108 *
3109 * @param int $size The size the image is to be
3110 */
3111function getSizedImageURL($size) {
3112	return getCustomImageURL($size);
3113}
3114
3115/**
3116 * Returns the url to the image with the dimensions you define with this function.
3117 *
3118 * @param int $size the size of the image to have
3119 * @param int $width width
3120 * @param int $height height
3121 * @param int $cropw crop width
3122 * @param int $croph crop height
3123 * @param int $cropx crop part x axis
3124 * @param int $cropy crop part y axis
3125 * @param bool $thumbStandin set true to inhibit watermarking
3126 * @param bool $effects image effects (e.g. set gray to force to grayscale)
3127 * @return string
3128 *
3129 * $size, $width, and $height are used in determining the final image size.
3130 * At least one of these must be provided. If $size is provided, $width and
3131 * $height are ignored. If both $width and $height are provided, the image
3132 * will have those dimensions regardless of the original image height/width
3133 * ratio. (Yes, this means that the image may be distorted!)
3134 *
3135 * The $crop* parameters determine the portion of the original image that
3136 * will be incorporated into the final image.
3137 *
3138 * $cropw and $croph "sizes" are typically proportional. That is you can
3139 * set them to values that reflect the ratio of width to height that you
3140 * want for the final image. Typically you would set them to the final
3141 * height and width. These values will always be adjusted so that they are
3142 * not larger than the original image dimensions.
3143 *
3144 * The $cropx and $cropy values represent the offset of the crop from the
3145 * top left corner of the image. If these values are provided, the $croph
3146 * and $cropw parameters are treated as absolute pixels not proportions of
3147 * the image. If cropx and cropy are not provided, the crop will be
3148 * "centered" in the image.
3149 *
3150 * When $cropx and $cropy are not provided the crop is offset from the top
3151 * left proportionally to the ratio of the final image size and the crop
3152 * size.
3153 *
3154 * Some typical croppings:
3155 *
3156 * $size=200, $width=NULL, $height=NULL, $cropw=200, $croph=100,
3157 * $cropx=NULL, $cropy=NULL produces an image cropped to a 2x1 ratio which
3158 * will fit in a 200x200 pixel frame.
3159 *
3160 * $size=NULL, $width=200, $height=NULL, $cropw=200, $croph=100, $cropx=100,
3161 * $cropy=10 will will take a 200x100 pixel slice from (10,100) of the
3162 * picture and create a 200x100 image
3163 *
3164 * $size=NULL, $width=200, $height=100, $cropw=200, $croph=120, $cropx=NULL,
3165 * $cropy=NULL will produce a (distorted) image 200x100 pixels from a 1x0.6
3166 * crop of the image.
3167 *
3168 * $size=NULL, $width=200, $height=NULL, $cropw=180, $croph=120, $cropx=NULL, $cropy=NULL
3169 * will produce an image that is 200x133 from a 1.5x1 crop that is 5% from the left
3170 * and 15% from the top of the image.
3171 *
3172  * @param int $size the size of the image to have
3173 * @param int $width width
3174 * @param int $height height
3175 * @param int $cropw crop width
3176 * @param int $croph crop height
3177 * @param int $cropx crop part x axis
3178 * @param int $cropy crop part y axis
3179 * @param bool $thumbStandin set true to inhibit watermarking
3180 * @param bool $effects image effects (e.g. set gray to force to grayscale)
3181 * @param obj $image optional image object, null means current image
3182 */
3183function getCustomImageURL($size, $width = NULL, $height = NULL, $cropw = NULL, $croph = NULL, $cropx = NULL, $cropy = NULL, $thumbStandin = false, $effects = NULL, $image = null) {
3184	global $_zp_current_image;
3185	if (is_null($image)) {
3186		$image = $_zp_current_image;
3187	}
3188	if (is_null($image)) {
3189		return false;
3190	}
3191	return $image->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $thumbStandin, $effects);
3192}
3193
3194/**
3195 * Print normal video or custom sized images.
3196 * Note: a class of 'not_visible' or 'password_protected' will be added as appropriate
3197 *
3198 * Notes on cropping:
3199 *
3200 * The $crop* parameters determine the portion of the original image that will be incorporated
3201 * into the final image. The w and h "sizes" are typically proportional. That is you can set them to
3202 * values that reflect the ratio of width to height that you want for the final image. Typically
3203 * you would set them to the fincal height and width.
3204 *
3205 * @param string $alt Alt text for the url
3206 * @param int $size size
3207 * @param int $width width
3208 * @param int $height height
3209 * @param int $cropw crop width
3210 * @param int $croph crop height
3211 * @param int $cropx crop x axis
3212 * @param int $cropy crop y axis
3213 * @param string $class Optional style class
3214 * @param string $id Optional style id
3215 * @param bool $thumbStandin set to true to treat as thumbnail
3216 * @param bool $effects image effects (e.g. set gray to force grayscale)
3217 * @param string $title Optional title attribute
3218 * @param string $type "image" (sizedimage) (default), "thumb" (thumbnail) required for using option settings for uncropped images
3219 * @param obj $image optional image object, null means current image
3220 * @param bool $maxspace true for maxspace, false default
3221 */
3222function printCustomSizedImage($alt, $size, $width = NULL, $height = NULL, $cropw = NULL, $croph = NULL, $cropx = NULL, $cropy = NULL, $class = NULL, $id = NULL, $thumbStandin = false, $effects = NULL, $title = null, $type = 'image', $image = null, $maxspace = false) {
3223	global $_zp_current_image;
3224	if (is_null($image)) {
3225		$image = $_zp_current_image;
3226	}
3227	if (is_null($image)) {
3228		return false;
3229	}
3230	if ($maxspace) {
3231		getMaxSpaceContainer($width, $height, $image);
3232	}
3233	if (empty($title)) {
3234		$title = $alt;
3235	}
3236	$attr = array(
3237			'alt' => html_encode($alt),
3238			'class' => $class,
3239			'title' => html_encode($title),
3240			'id' => $id,
3241			'loading' => 'lazy'
3242	);
3243	if (!$image->isPublished()) {
3244		$attr['class'] .= " not_visible";
3245	}
3246	$album = $image->getAlbum();
3247	$pwd = $album->getPassword();
3248	if (!empty($pwd)) {
3249		$attr['class'] .= " password_protected";
3250	}
3251	if ($size && !$maxspace) {
3252		$type = 'image';
3253		if ($thumbStandin) {
3254			$type = 'thumb';
3255		}
3256		$dims = getSizeCustomImage($size, null, null, null, null, null, null, $image, $type);
3257		$attr['width'] = $dims[0];
3258		$attr['height'] = $dims[1];
3259	} else {
3260		$attr['width'] = $width;
3261		$attr['height'] = $height;
3262	}
3263	if (isImagePhoto($image) || $thumbStandin) {
3264		if ($maxspace) {
3265			$attr['src'] = html_pathurlencode($image->getCustomImage(null, $width, $height, NULL, NULL, NULL, NULL, $thumbStandin, $effects));
3266		} else {
3267			$attr['src'] = html_pathurlencode($image->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $thumbStandin, $effects));
3268		}
3269		$attr_filtered = zp_apply_filter('custom_image_attr', $attr, $image);
3270		$attributes = generateAttributesFromArray($attr_filtered);
3271		$html = '<img ' . $attributes . ' />';
3272		$html = zp_apply_filter('custom_image_html', $html, $thumbStandin, $image);
3273		echo $html;
3274	} else { // better be a plugin
3275		echo $image->getContent($width, $height);
3276	}
3277}
3278
3279/**
3280 * Returns a link to a un-cropped custom sized version of the current image within the given height and width dimensions.
3281 * Use for sized images.
3282 *
3283 * @param int $width width
3284 * @param int $height height
3285 * @return string
3286 */
3287function getCustomSizedImageMaxSpace($width, $height) {
3288	global $_zp_current_image;
3289	if (is_null($_zp_current_image))
3290		return false;
3291	getMaxSpaceContainer($width, $height, $_zp_current_image);
3292	return getCustomImageURL(NULL, $width, $height);
3293}
3294
3295/**
3296 * Returns a link to a un-cropped custom sized version of the current image within the given height and width dimensions.
3297 * Use for sized thumbnails.
3298 *
3299 * @param int $width width
3300 * @param int $height height
3301 * @return string
3302 */
3303function getCustomSizedImageThumbMaxSpace($width, $height) {
3304	global $_zp_current_image;
3305	if (is_null($_zp_current_image))
3306		return false;
3307	getMaxSpaceContainer($width, $height, $_zp_current_image, true);
3308	return getCustomImageURL(NULL, $width, $height, NULL, NULL, NULL, NULL, true);
3309}
3310
3311/**
3312 * Creates image thumbnails which will fit un-cropped within the width & height parameters given
3313 *
3314 * @param string $alt Alt text for the url
3315 * @param int $width width
3316 * @param int $height height
3317 * @param string $class Optional style class
3318 * @param string $id Optional style id
3319 * @param string $title optional title attribute
3320 * @param obj $image optional image object, null means current image
3321 */
3322function printCustomSizedImageThumbMaxSpace($alt, $width, $height, $class = NULL, $id = NULL, $title = null, $image = null) {
3323	global $_zp_current_image;
3324	if (is_null($image))
3325		$image = $_zp_current_image;
3326	if (is_null($image))
3327		return false;
3328	printCustomSizedImage($alt, NULL, $width, $height,  NULL,  NULL, NULL,  NULL, $class, $id, true, NULL, $title, 'thumb', $image, true);
3329}
3330
3331/**
3332 * Print normal video or un-cropped within the given height and width dimensions. Use for sized images or thumbnails in an album.
3333 * Note: a class of 'not_visible' or 'password_protected' will be added as appropriate
3334 *
3335 * @param string $alt Alt text for the url
3336 * @param int $width width
3337 * @param int $height height
3338 * @param string $class Optional style class
3339 * @param string $id Optional style id
3340 * @param string $title optional title attribute
3341 * @param obj $image optional image object, null means current image
3342 */
3343function printCustomSizedImageMaxSpace($alt, $width, $height, $class = NULL, $id = NULL, $thumb = false, $title = null, $image = null) {
3344	global $_zp_current_image;
3345	if (is_null($image))
3346		$image = $_zp_current_image;
3347	if (is_null($image))
3348		return false;
3349	printCustomSizedImage($alt, NULL, $width, $height,  NULL,  NULL, NULL,  NULL, $class, $id, $thumb, NULL, $title, 'image', $image, true);
3350}
3351
3352/**
3353 * Prints link to an image of specific size
3354 * @param int $size how big
3355 * @param string $text URL text
3356 * @param string $title URL title
3357 * @param string $class optional URL class
3358 * @param string $id optional URL id
3359 */
3360function printSizedImageURL($size, $text, $title, $class = NULL, $id = NULL) {
3361	printLinkHTML(getSizedImageURL($size), $text, $title, $class, $id);
3362}
3363
3364/**
3365 * Returns a list of tags for context of the page called where called
3366 *
3367 * @return string
3368 * @since 1.1
3369 */
3370function getTags() {
3371	if (in_context(ZP_IMAGE)) {
3372		global $_zp_current_image;
3373		return $_zp_current_image->getTags();
3374	} else if (in_context(ZP_ALBUM)) {
3375		global $_zp_current_album;
3376		return $_zp_current_album->getTags();
3377	} else if (in_context(ZP_ZENPAGE_PAGE)) {
3378		global $_zp_current_zenpage_page;
3379		return $_zp_current_zenpage_page->getTags();
3380	} else if (in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
3381		global $_zp_current_zenpage_news;
3382		return $_zp_current_zenpage_news->getTags();
3383	}
3384	return array();
3385}
3386
3387/**
3388 * Prints a list of tags, editable by admin
3389 *
3390 * @param string $option links by default, if anything else the
3391 *               tags will not link to all other images with the same tag
3392 * @param string $preText text to go before the printed tags
3393 * @param string $class css class to apply to the div surrounding the UL list
3394 * @param string $separator what charactor shall separate the tags
3395 * @since 1.1
3396 */
3397function printTags($option = 'links', $preText = NULL, $class = NULL, $separator = ', ') {
3398	global $_zp_current_search;
3399	if (is_null($class)) {
3400		$class = 'taglist';
3401	}
3402	$singletag = getTags();
3403	$tagstring = implode(', ', $singletag);
3404	if ($tagstring === '' or $tagstring === NULL) {
3405		$preText = '';
3406	}
3407	if (in_context(ZP_IMAGE)) {
3408		$object = "image";
3409	} else if (in_context(ZP_ALBUM)) {
3410		$object = "album";
3411	} else if (in_context(ZP_ZENPAGE_PAGE)) {
3412		$object = "pages";
3413	} else if (in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
3414		$object = "news";
3415	}
3416	if (count($singletag) > 0) {
3417		if (!empty($preText)) {
3418			echo "<span class=\"tags_title\">" . $preText . "</span>";
3419		}
3420		echo "<ul class=\"" . $class . "\">\n";
3421		if (is_object($_zp_current_search)) {
3422			$albumlist = $_zp_current_search->getAlbumList();
3423		} else {
3424			$albumlist = NULL;
3425		}
3426		$ct = count($singletag);
3427		$x = 0;
3428		foreach ($singletag as $atag) {
3429			if (++$x == $ct) {
3430				$separator = "";
3431			}
3432			if ($option === "links") {
3433				$links1 = "<a href=\"" . html_encode(getSearchURL(search_quote($atag), '', 'tags', 0, array('albums' => $albumlist))) . "\" title=\"" . html_encode($atag) . "\">";
3434				$links2 = "</a>";
3435			} else {
3436				$links1 = $links2 = '';
3437			}
3438			echo "\t<li>" . $links1 . $atag . $links2 . $separator . "</li>\n";
3439		}
3440		echo "</ul>";
3441	} else {
3442		echo "$tagstring";
3443	}
3444}
3445
3446/**
3447 * Either prints all of the galleries tgs as a UL list or a cloud
3448 *
3449 * @param string $option "cloud" for tag cloud, "list" for simple list
3450 * @param string $class CSS class
3451 * @param string $sort "results" for relevance list, "random" for random ordering, otherwise the list is alphabetical
3452 * @param bool $counter TRUE if you want the tag count within brackets behind the tag
3453 * @param bool $links set to TRUE to have tag search links included with the tag.
3454 * @param int $maxfontsize largest font size the cloud should display
3455 * @param int $maxcount the floor count for setting the cloud font size to $maxfontsize
3456 * @param int $mincount the minimum count for a tag to appear in the output
3457 * @param int $limit set to limit the number of tags displayed to the top $numtags
3458 * @param int $minfontsize minimum font size the cloud should display
3459 * @param bool $exclude_unassigned True or false if you wish to exclude tags that are not assigne to any item (default: true)
3460 * @param bool $checkaccess True or false (default: false) if you wish to exclude tags that are assigned to items (or are not assigned at all) the visitor is not allowed to see
3461 * Beware that this may cause overhead on large sites. Usage of the static_html_cache is strongely recommended then.
3462 * @since 1.1
3463 */
3464function printAllTagsAs($option, $class = '', $sort = NULL, $counter = FALSE, $links = TRUE, $maxfontsize = 2, $maxcount = 50, $mincount = 1, $limit = NULL, $minfontsize = 0.8, $exclude_unassigned = true, $checkaccess = false) {
3465	global $_zp_current_search;
3466	$option = strtolower($option);
3467	if ($class != "") {
3468		$class = ' class="' . $class . '"';
3469	}
3470	$tagcount = getAllTagsCount($exclude_unassigned, $checkaccess);
3471	if (!is_array($tagcount)) {
3472		return false;
3473	}
3474	switch ($sort) {
3475		case 'results':
3476			arsort($tagcount);
3477			if (!is_null($limit)) {
3478				$tagcount = array_slice($tagcount, 0, $limit);
3479			}
3480			break;
3481		case 'random':
3482			if (!is_null($limit)) {
3483				$tagcount = array_slice($tagcount, 0, $limit);
3484			}
3485			shuffle_assoc($tagcount);
3486			break;
3487		default:
3488			break;
3489	}
3490	?>
3491	<ul<?php echo $class; ?>>
3492		<?php
3493		if (count($tagcount) > 0) {
3494			foreach ($tagcount as $key => $val) {
3495				if (!$counter) {
3496					$counter = "";
3497				} else {
3498					$counter = " (" . $val . ") ";
3499				}
3500				if ($option == "cloud") { // calculate font sizes, formula from wikipedia
3501					if ($val <= $mincount) {
3502						$size = $minfontsize;
3503					} else {
3504						$size = min(max(round(($maxfontsize * ($val - $mincount)) / ($maxcount - $mincount), 2), $minfontsize), $maxfontsize);
3505					}
3506					$size = str_replace(',', '.', $size);
3507					$size = ' style="font-size:' . $size . 'em;"';
3508				} else {
3509					$size = '';
3510				}
3511				if ($val >= $mincount) {
3512					if ($links) {
3513						if (is_object($_zp_current_search)) {
3514							$albumlist = $_zp_current_search->getAlbumList();
3515						} else {
3516							$albumlist = NULL;
3517						}
3518						$link = getSearchURL(search_quote($key), '', 'tags', 0, array('albums' => $albumlist));
3519						?>
3520						<li>
3521							<a href="<?php echo html_encode($link); ?>"<?php echo $size; ?>><?php echo $key . $counter; ?></a>
3522						</li>
3523						<?php
3524					} else {
3525						?>
3526						<li<?php echo $size; ?>><?php echo $key . $counter; ?></li>
3527						<?php
3528					}
3529				}
3530			} // while end
3531		} else {
3532			?>
3533			<li><?php echo gettext('No popular tags'); ?></li>
3534			<?php
3535		}
3536		?>
3537	</ul>
3538	<?php
3539}
3540
3541/**
3542 * Retrieves a list of all unique years & months from the images in the gallery
3543 *
3544 * @param string $order set to 'desc' for the list to be in descending order
3545 * @return array
3546 */
3547function getAllDates($order = 'asc') {
3548	$alldates = array();
3549	$cleandates = array();
3550	$sql = "SELECT `date` FROM " . prefix('images');
3551	if (!zp_loggedin()) {
3552		$sql .= " WHERE `show` = 1";
3553	}
3554	$hidealbums = getNotViewableAlbums();
3555	if (!is_null($hidealbums)) {
3556		if (zp_loggedin()) {
3557			$sql .= ' WHERE ';
3558		} else {
3559			$sql .= ' AND ';
3560		}
3561		foreach ($hidealbums as $id) {
3562			$sql .= '`albumid`!=' . $id . ' AND ';
3563		}
3564		$sql = substr($sql, 0, -5);
3565	}
3566	$result = query($sql);
3567	if ($result) {
3568		while ($row = db_fetch_assoc($result)) {
3569			$alldates[] = $row['date'];
3570		}
3571		db_free_result($result);
3572	}
3573	foreach ($alldates as $adate) {
3574		if (!empty($adate)) {
3575			$cleandates[] = substr($adate, 0, 7) . "-01";
3576		}
3577	}
3578	$datecount = array_count_values($cleandates);
3579	if ($order == 'desc') {
3580		krsort($datecount);
3581	} else {
3582		ksort($datecount);
3583	}
3584	return $datecount;
3585}
3586
3587/**
3588 * Prints a compendum of dates and links to a search page that will show results of the date
3589 *
3590 * @param string $class optional class
3591 * @param string $yearid optional class for "year"
3592 * @param string $monthid optional class for "month"
3593 * @param string $order set to 'desc' for the list to be in descending order
3594 */
3595function printAllDates($class = 'archive', $yearid = 'year', $monthid = 'month', $order = 'asc') {
3596	global $_zp_current_search, $_zp_gallery_page;
3597	if (empty($class)) {
3598		$classactive = 'archive_active';
3599	} else {
3600		$classactive = $class . '_active';
3601		$class = 'class="' . $class . '"';
3602	}
3603	if ($_zp_gallery_page == 'search.php') {
3604		$activedate = getSearchDate('%Y-%m');
3605	} else {
3606		$activedate = '';
3607	}
3608	if (!empty($yearid)) {
3609		$yearid = 'class="' . $yearid . '"';
3610	}
3611	if (!empty($monthid)) {
3612		$monthid = 'class="' . $monthid . '"';
3613	}
3614	$datecount = getAllDates($order);
3615	$lastyear = "";
3616	echo "\n<ul $class>\n";
3617	$nr = 0;
3618	foreach($datecount as $key => $val) {
3619		$nr++;
3620		if ($key == '0000-00-01') {
3621			$year = "no date";
3622			$month = "";
3623		} else {
3624			$dt = strftime('%Y-%B', strtotime($key));
3625			$year = substr($dt, 0, 4);
3626			$month = substr($dt, 5);
3627		}
3628
3629		if ($lastyear != $year) {
3630			$lastyear = $year;
3631			if ($nr != 1) {
3632				echo "</ul>\n</li>\n";
3633			}
3634			echo "<li $yearid>$year\n<ul $monthid>\n";
3635		}
3636		if (is_object($_zp_current_search)) {
3637			$albumlist = $_zp_current_search->getAlbumList();
3638		} else {
3639			$albumlist = NULL;
3640		}
3641		$datekey = substr($key, 0, 7);
3642		if ($activedate = $datekey) {
3643			$cl = ' class="' . $classactive . '"';
3644		} else {
3645			$cl = '';
3646		}
3647		echo '<li' . $cl . '><a href="' . html_encode(getSearchURL('', $datekey, '', 0, array('albums' => $albumlist))) . '">' . $month . ' (' . $val . ')</a></li>' . "\n";
3648	}
3649	echo "</ul>\n</li>\n</ul>\n";
3650}
3651
3652/**
3653 * Produces the url to a custom page (e.g. one that is not album.php, image.php, or index.php)
3654 *
3655 * @param string $page page name to include in URL
3656 * @param string $q query string to add to url
3657 * @param bool $webpath host path to be prefixed. If "false" is passed you will get a localized "WEBPATH"
3658 * @return string
3659 */
3660function getCustomPageURL($page, $q = '', $webpath = null) {
3661	global $_zp_conf_vars;
3662	if (array_key_exists($page, $_zp_conf_vars['special_pages'])) {
3663		$rewrite = preg_replace('~^_PAGE_/~', _PAGE_ . '/', $_zp_conf_vars['special_pages'][$page]['rewrite']) . '/';
3664	} else {
3665		$rewrite = '/' . _PAGE_ . '/' . $page . '/';
3666	}
3667	$plain = "index.php?p=$page";
3668	if (!empty($q)) {
3669		$rewrite .= "?$q";
3670		$plain .= "&$q";
3671	}
3672	return zp_apply_filter('getLink', rewrite_path($rewrite, $plain, $webpath), $page . '.php', null);
3673}
3674
3675/**
3676 * Prints the url to a custom page (e.g. one that is not album.php, image.php, or index.php)
3677 *
3678 * @param string $linktext Text for the URL
3679 * @param string $page page name to include in URL
3680 * @param string $q query string to add to url
3681 * @param string $prev text to insert before the URL
3682 * @param string $next text to follow the URL
3683 * @param string $class optional class
3684 */
3685function printCustomPageURL($linktext, $page, $q = '', $prev = '', $next = '', $class = NULL) {
3686	if (!is_null($class)) {
3687		$class = 'class="' . $class . '"';
3688	}
3689	echo $prev . "<a href=\"" . html_encode(getCustomPageURL($page, $q)) . "\" $class title=\"" . html_encode($linktext) . "\">" . html_encode($linktext) . "</a>" . $next;
3690}
3691
3692//*** Search functions *******************************************************
3693//****************************************************************************
3694
3695/**
3696 * tests if a search page is an "archive" page
3697 *
3698 * @return bool
3699 */
3700function isArchive() {
3701	return isset($_REQUEST['date']);
3702}
3703
3704/**
3705 * Returns a search URL
3706 *
3707 * @param mixed $words the search words target
3708 * @param mixed $dates the dates that limit the search
3709 * @param mixed $fields the fields on which to search
3710 * @param int $page the page number for the URL
3711 * @param array $object_list the list of objects to search
3712 * @return string
3713 * @since 1.1.3
3714 */
3715function getSearchURL($words, $dates, $fields, $page, $object_list = NULL) {
3716	$urls = '';
3717	$rewrite = false;
3718	if (MOD_REWRITE) {
3719		$rewrite = true;
3720		if (is_array($object_list)) {
3721			foreach ($object_list as $obj) {
3722				if ($obj) {
3723					$rewrite = false;
3724					break;
3725				}
3726			}
3727		}
3728	}
3729
3730	if ($rewrite) {
3731		if (empty($dates)) {
3732			$url = SEO_WEBPATH . '/' . _SEARCH_ . '/';
3733		} else {
3734			$url = SEO_WEBPATH . '/' . _ARCHIVE_ . '/';
3735		}
3736	} else {
3737		$url = SEO_WEBPATH . "/index.php?p=search";
3738	}
3739	if (!empty($fields) && empty($dates)) {
3740		if (!is_array($fields)) {
3741			$fields = explode(',', $fields);
3742		}
3743		$temp = $fields;
3744		if ($rewrite && count($fields) == 1 && array_shift($temp) == 'tags') {
3745			$url = SEO_WEBPATH . '/' . _TAGS_ . '/';
3746		} else {
3747			$search = new SearchEngine();
3748			$urls = $search->getSearchFieldsText($fields, 'searchfields=');
3749		}
3750	}
3751
3752	if (!empty($words)) {
3753		if (is_array($words)) {
3754			foreach ($words as $key => $word) {
3755				$words[$key] = search_quote($word);
3756			}
3757			$words = implode(',', $words);
3758		}
3759		$words = strtr($words, array('%' => '__25__', '&' => '__26__', '#' => '__23__', '/' => '__2F__'));
3760		if ($rewrite) {
3761			$url .= urlencode($words) . '/';
3762		} else {
3763			$url .= "&words=" . urlencode($words);
3764		}
3765	}
3766	if (!empty($dates)) {
3767		if (is_array($dates)) {
3768			$dates = implode(',', $dates);
3769		}
3770		if ($rewrite) {
3771			$url .= $dates . '/';
3772		} else {
3773			$url .= "&date=$dates";
3774		}
3775	}
3776	if ($page > 1) {
3777		if ($rewrite) {
3778			$url .= "$page/";
3779		} else {
3780			if ($urls) {
3781				$urls .= '&';
3782			}
3783			$urls .= "page=$page";
3784		}
3785	}
3786	if (!empty($urls)) {
3787		if ($rewrite) {
3788			$url .= '?' . $urls;
3789		} else {
3790			$url .= '&' . $urls;
3791		}
3792	}
3793	if (is_array($object_list)) {
3794		foreach ($object_list as $key => $list) {
3795			if (!empty($list)) {
3796				$url .= '&in' . $key . '=' . html_encode(implode(',', $list));
3797			}
3798		}
3799	}
3800	return $url;
3801}
3802
3803/**
3804 * Prints the search form
3805 *
3806 * Search works on a list of tokens entered into the search form.
3807 *
3808 * Tokens may be part of boolean expressions using &, |, !, and parens. (Comma is retained as a synonom of | for
3809 * backwords compatibility.)
3810 *
3811 * Tokens may be enclosed in quotation marks to create exact pattern matches or to include the boolean operators and
3812 * parens as part of the tag..
3813 *
3814 * @param string $prevtext text to go before the search form
3815 * @param string $id css id for the search form, default is 'search'
3816 * @param string $buttonSource optional path to the image for the button or if not a path to an image,
3817 * 											this will be the button hint
3818 * @param string $buttontext optional text for the button ("Search" will be the default text)
3819 * @param string $iconsource optional theme based icon for the search fields toggle
3820 * @param array $query_fields override selection for enabled fields with this list
3821 * @param array $objects_list optional array of things to search eg. [albums]=>[list], etc.
3822 * 														if the list is simply 0, the objects will be omitted from the search
3823 * @param string $within set to true to search within current results, false to search fresh
3824 * @since 1.1.3
3825 */
3826function printSearchForm($prevtext = NULL, $id = 'search', $buttonSource = NULL, $buttontext = '', $iconsource = NULL, $query_fields = NULL, $object_list = NULL, $within = NULL) {
3827	global $_zp_adminJS_loaded, $_zp_current_search;
3828	$engine = new SearchEngine();
3829	if (!is_null($_zp_current_search) && !$_zp_current_search->getSearchWords()) {
3830		$engine->clearSearchWords();
3831	}
3832	if (!is_null($object_list)) {
3833		if (array_key_exists(0, $object_list)) { // handle old form albums list
3834			trigger_error(gettext('printSearchForm $album_list parameter is deprecated. Pass array("albums"=>array(album, album, ...)) instead.'), E_USER_NOTICE);
3835			$object_list = array('albums' => $object_list);
3836		}
3837	}
3838	if (empty($buttontext)) {
3839		$buttontext = gettext("Search");
3840	}
3841	$zf = WEBPATH . "/" . ZENFOLDER;
3842	$searchwords = $engine->codifySearchString();
3843	if (substr($searchwords, -1, 1) == ',') {
3844		$searchwords = substr($searchwords, 0, -1);
3845	}
3846	$hint = $hintJS = '%s';
3847	if (empty($searchwords)) {
3848		$within = false;
3849	} else {
3850		$hintJS = gettext('%s within previous results');
3851	}
3852	if (is_null($within)) {
3853		$within = getOption('search_within');
3854	}
3855	if ($within) {
3856		$hint = gettext('%s within previous results');
3857	}
3858	if (preg_match('!\/(.*)[\.png|\.jpg|\.jpeg|\.gif]$!', $buttonSource)) {
3859		$buttonSource = 'src="' . $buttonSource . '" alt="' . $buttontext . '"';
3860		$button = 'title="' . sprintf($hint, $buttontext) . '"';
3861		$type = 'image';
3862	} else {
3863		$type = 'submit';
3864		if ($buttonSource) {
3865			$button = 'value="' . $buttontext . '" title="' . sprintf($hint, $buttonSource) . '"';
3866			$buttonSource = '';
3867		} else {
3868			$button = 'value="' . $buttontext . '" title="' . sprintf($hint, $buttontext) . '"';
3869		}
3870	}
3871	if (empty($iconsource)) {
3872		$iconsource = WEBPATH . '/' . ZENFOLDER . '/images/searchfields_icon.png';
3873	}
3874	if (MOD_REWRITE) {
3875		$searchurl = SEO_WEBPATH . '/' . _SEARCH_ . '/';
3876	} else {
3877		$searchurl = WEBPATH . "/index.php?p=search";
3878	}
3879	if (!$within) {
3880		$engine->clearSearchWords();
3881	}
3882
3883	$fields = $engine->allowedSearchFields();
3884	if (!$_zp_adminJS_loaded) {
3885		$_zp_adminJS_loaded = true;
3886		?>
3887		<script type="text/javascript" src="<?php echo WEBPATH . '/' . ZENFOLDER; ?>/js/admin.js"></script>
3888		<?php
3889	}
3890	?>
3891	<div id="<?php echo $id; ?>">
3892		<!-- search form -->
3893		<form method="post" action="<?php echo $searchurl; ?>" id="search_form">
3894			<script type="text/javascript">
3895			// <!-- <![CDATA[
3896			var within = <?php echo (int) $within; ?>;
3897			function search_(way) {
3898				within = way;
3899				if (way) {
3900					$('#search_submit').attr('title', '<?php echo sprintf($hintJS, $buttontext); ?>');
3901				} else {
3902					lastsearch = '';
3903					$('#search_submit').attr('title', '<?php echo $buttontext; ?>');
3904				}
3905				$('#search_input').val('');
3906			}
3907			$('#search_form').submit(function() {
3908				if (within) {
3909					var newsearch = $.trim($('#search_input').val());
3910					if (newsearch.substring(newsearch.length - 1) == ',') {
3911						newsearch = newsearch.substr(0, newsearch.length - 1);
3912					}
3913					if (newsearch.length > 0) {
3914						$('#search_input').val('(<?php echo $searchwords; ?>) AND (' + newsearch + ')');
3915					} else {
3916						$('#search_input').val('<?php echo $searchwords; ?>');
3917					}
3918				}
3919				return true;
3920			});
3921    $(document).ready(function() {
3922      $( $("#checkall_searchfields") ).on( "click", function() {
3923        $("#searchextrashow :checkbox").prop("checked", $("#checkall_searchfields").prop("checked") );
3924      });
3925    });
3926			// ]]> -->
3927			</script>
3928			<?php echo $prevtext; ?>
3929			<div>
3930				<span class="tagSuggestContainer">
3931					<input type="text" name="words" value="" id="search_input" size="10" />
3932				</span>
3933				<?php if (count($fields) > 1 || $searchwords) { ?>
3934					<a class="toggle_searchextrashow" href="#"><img src="<?php echo $iconsource; ?>" title="<?php echo gettext('search options'); ?>" alt="<?php echo gettext('fields'); ?>" id="searchfields_icon" /></a>
3935					<script>
3936						$(".toggle_searchextrashow").click(function(event) {
3937							event.preventDefault();
3938							$("#searchextrashow").toggle();
3939						});
3940					</script>
3941				<?php } ?>
3942				<input type="<?php echo $type; ?>" <?php echo $button; ?> class="button buttons" id="search_submit" <?php echo $buttonSource; ?> data-role="none" />
3943				<?php
3944				if (is_array($object_list)) {
3945					foreach ($object_list as $key => $list) {
3946						?>
3947						<input type="hidden" name="in<?php echo $key ?>" value="<?php
3948						if (is_array($list))
3949							echo html_encode(implode(',', $list));
3950						else
3951							echo html_encode($list);
3952						?>" />
3953									 <?php
3954								 }
3955							 }
3956							 ?>
3957				<br />
3958				<?php
3959				if (count($fields) > 1 || $searchwords) {
3960					$fields = array_flip($fields);
3961					sortArray($fields);
3962					$fields = array_flip($fields);
3963					if (is_null($query_fields)) {
3964						$query_fields = $engine->parseQueryFields();
3965					} else {
3966						if (!is_array($query_fields)) {
3967							$query_fields = $engine->numericFields($query_fields);
3968						}
3969					}
3970					if (count($query_fields) == 0) {
3971						$query_fields = $engine->allowedSearchFields();
3972					}
3973					?>
3974					<div style="display:none;" id="searchextrashow">
3975						<?php
3976						if ($searchwords) {
3977							?>
3978							<label>
3979								<input type="radio" name="search_within" id="search_within-1" value="1"<?php if ($within) echo ' checked="checked"'; ?> onclick="search_(1);" />
3980								<?php echo gettext('Within'); ?>
3981							</label>
3982							<label>
3983								<input type="radio" name="search_within" id="search_within-0" value="1"<?php if (!$within) echo ' checked="checked"'; ?> onclick="search_(0);" />
3984								<?php echo gettext('New'); ?>
3985							</label>
3986							<?php
3987						}
3988						if (count($fields) > 1) {
3989							?>
3990							<ul>
3991        <li><label><input type="checkbox" name="checkall_searchfields" id="checkall_searchfields" checked="checked">* <?php echo gettext('Check/uncheck all'); ?> *</label></li>
3992								<?php
3993								foreach ($fields as $display => $key) {
3994									echo '<li><label><input id="SEARCH_' . html_encode($key) . '" name="SEARCH_' . html_encode($key) . '" type="checkbox"';
3995									if (in_array($key, $query_fields)) {
3996										echo ' checked="checked" ';
3997									}
3998									echo ' value="' . html_encode($key) . '"  /> ' . html_encode($display) . "</label></li>" . "\n";
3999								}
4000								?>
4001							</ul>
4002							<?php
4003						}
4004						?>
4005					</div>
4006					<?php
4007				}
4008				?>
4009			</div>
4010		</form>
4011	</div><!-- end of search form -->
4012	<?php
4013}
4014
4015/**
4016 * Returns the a sanitized version of the search string
4017 *
4018 * @return string
4019 * @since 1.1
4020 */
4021function getSearchWords() {
4022	global $_zp_current_search;
4023	if (!in_context(ZP_SEARCH))
4024		return '';
4025	return stripcslashes($_zp_current_search->codifySearchString());
4026}
4027
4028/**
4029 * Returns the date of the search
4030 *
4031 * @param string $format formatting of the date, default 'F Y'
4032 * @return string
4033 * @since 1.1
4034 */
4035function getSearchDate($format = '%B %Y') {
4036	if (in_context(ZP_SEARCH)) {
4037		global $_zp_current_search;
4038		$date = $_zp_current_search->getSearchDate();
4039		if (empty($date)) {
4040			return "";
4041		}
4042		if ($date == '0000-00') {
4043			return gettext("no date");
4044		};
4045		$dt = strtotime($date . "-01");
4046		return zpFormattedDate($format, $dt);
4047	}
4048	return false;
4049}
4050
4051/**
4052 * controls the thumbnail layout of themes.
4053 *
4054 * Uses the theme options:
4055 * 	albums_per_row
4056 * 	albums_per_page
4057 * 	images_per_row
4058 * 	images_per_page
4059 *
4060 * Computes a normalized images/albums per page and computes the number of
4061 * images that will fit on the "transitional" page between album thumbs and
4062 * image thumbs. This function is "internal" and is called from the root
4063 * index.php script before the theme script is loaded.
4064 */
4065function setThemeColumns() {
4066	global $_zp_current_album, $_firstPageImages, $_oneImagePage;
4067	$_firstPageImages = false;
4068	if (($albumColumns = getOption('albums_per_row')) <= 1)
4069		$albumColumns = false;
4070	if (($imageColumns = getOption('images_per_row')) <= 1)
4071		$imageColumns = false;
4072	$albcount = max(1, getOption('albums_per_page'));
4073	if (($albumColumns) && (($albcount % $albumColumns) != 0)) {
4074		setOption('albums_per_page', $albcount = ((floor($albcount / $albumColumns) + 1) * $albumColumns), false);
4075	}
4076	$imgcount = max(1, getOption('images_per_page'));
4077	if (($imageColumns) && (($imgcount % $imageColumns) != 0)) {
4078		setOption('images_per_page', $imgcount = ((floor($imgcount / $imageColumns) + 1) * $imageColumns), false);
4079	}
4080	if ((getOption('thumb_transition') && !$_oneImagePage) && in_context(ZP_ALBUM | ZP_SEARCH) && $albumColumns && $imageColumns) {
4081		$count = getNumAlbums();
4082		if ($count == 0) {
4083			$_firstPageImages = 0;
4084		}
4085		$rowssused = ceil(($count % $albcount) / $albumColumns); /* number of album rows unused */
4086		$leftover = floor(max(1, getOption('images_per_page')) / $imageColumns) - $rowssused;
4087		$_firstPageImages = max(0, $leftover * $imageColumns); /* number of images that fill the leftover rows */
4088		if ($_firstPageImages == $imgcount) {
4089			$_firstPageImages = 0;
4090		}
4091	}
4092}
4093
4094//************************************************************************************************
4095// album password handling
4096//************************************************************************************************
4097
4098/**
4099 * returns the auth type of a guest login
4100 *
4101 * @param string $hint
4102 * @param string $show
4103 * @return string
4104 */
4105function checkForGuest(&$hint = NULL, &$show = NULL) {
4106	global $_zp_gallery, $_zp_gallery_page, $_zp_current_zenpage_page, $_zp_current_category, $_zp_current_zenpage_news;
4107	$authType = zp_apply_filter('checkForGuest', NULL);
4108	if (!is_null($authType))
4109		return $authType;
4110	if (in_context(ZP_SEARCH)) { // search page
4111		$hash = getOption('search_password');
4112		if (getOption('search_user') != '')
4113			$show = true;
4114		$hint = get_language_string(getOption('search_hint'));
4115		$authType = 'zpcms_auth_search';
4116		if (empty($hash)) {
4117			$hash = $_zp_gallery->getPassword();
4118			if ($_zp_gallery->getUser() != '')
4119				$show = true;
4120			$hint = $_zp_gallery->getPasswordHint();
4121			$authType = 'zpcms_auth_gallery';
4122		}
4123		if (!empty($hash) && zp_getCookie($authType) == $hash) {
4124			return $authType;
4125		}
4126	} else if (!is_null($_zp_current_zenpage_news)) {
4127		$authType = $_zp_current_zenpage_news->checkAccess($hint, $show);
4128		return $authType;
4129	} else if (isset($_GET['album'])) { // album page
4130		list($album, $image) = rewrite_get_album_image('album', 'image');
4131		if ($authType = checkAlbumPassword($album, $hint)) {
4132			return $authType;
4133		} else {
4134			$alb = newAlbum($album);
4135			if ($alb->getUser() != '')
4136				$show = true;
4137			return false;
4138		}
4139	} else { // other page
4140		$hash = $_zp_gallery->getPassword();
4141		if ($_zp_gallery->getUser() != '')
4142			$show = true;
4143		$hint = $_zp_gallery->getPasswordHint();
4144		if (!empty($hash) && zp_getCookie('zpcms_auth_gallery') == $hash) {
4145			return 'zpcms_auth_gallery';
4146		}
4147	}
4148	if (empty($hash))
4149		return 'zp_public_access';
4150	return false;
4151}
4152
4153/**
4154 * Checks to see if a password is needed
4155 *
4156 * Returns true if access is allowed
4157 *
4158 * The password protection is hereditary. This normally only impacts direct url access to an object since if
4159 * you are going down the tree you will be stopped at the first place a password is required.
4160 *
4161 *
4162 * @param string $hint the password hint
4163 * @param bool $show whether there is a user associated with the password.
4164 * @return bool
4165 * @since 1.1.3
4166 */
4167function checkAccess(&$hint = NULL, &$show = NULL) {
4168	global $_zp_current_album, $_zp_current_search, $_zp_gallery, $_zp_gallery_page,
4169	$_zp_current_zenpage_page, $_zp_current_zenpage_news;
4170	if (GALLERY_SECURITY != 'public') // only registered users allowed
4171		$show = true; //	therefore they will need to supply their user id is something fails below
4172
4173	if ($_zp_gallery->isUnprotectedPage(stripSuffix($_zp_gallery_page)))
4174		return true;
4175	if (zp_loggedin()) {
4176		$fail = zp_apply_filter('isMyItemToView', NULL);
4177		if (!is_null($fail)) { //	filter had something to say about access, honor it
4178			return $fail;
4179		}
4180		switch ($_zp_gallery_page) {
4181			case 'album.php':
4182			case 'image.php':
4183				if ($_zp_current_album->isMyItem(LIST_RIGHTS)) {
4184					return true;
4185				}
4186				break;
4187			case 'search.php':
4188				if (zp_loggedin(VIEW_SEARCH_RIGHTS)) {
4189					return true;
4190				}
4191				break;
4192			default:
4193				if (zp_loggedin(VIEW_GALLERY_RIGHTS)) {
4194					return true;
4195				}
4196				break;
4197		}
4198	}
4199	if (GALLERY_SECURITY == 'public' && ($access = checkForGuest($hint, $show))) {
4200		return $access; // public page or a guest is logged in
4201	}
4202	return false;
4203}
4204
4205/**
4206 * Returns a redirection link for the password form
4207 *
4208 * @return string
4209 */
4210function getPageRedirect() {
4211  global $_zp_login_error, $_zp_password_form_printed, $_zp_current_search, $_zp_gallery_page,
4212  $_zp_current_album, $_zp_current_image, $_zp_current_zenpage_news;
4213	if($_zp_login_error !== 2) {
4214		return false;
4215	}
4216  switch ($_zp_gallery_page) {
4217    case 'index.php':
4218      $action = '/index.php';
4219      break;
4220    case 'album.php':
4221      $action = '/index.php?userlog=1&album=' . pathurlencode($_zp_current_album->name);
4222      break;
4223    case 'image.php':
4224      $action = '/index.php?userlog=1&album=' . pathurlencode($_zp_current_album->name) . '&image=' . urlencode($_zp_current_image->filename);
4225      break;
4226    case 'pages.php':
4227      $action = '/index.php?userlog=1&p=pages&title=' . urlencode(getPageTitlelink());
4228      break;
4229    case 'news.php':
4230      $action = '/index.php?userlog=1&p=news';
4231      if (!is_null($_zp_current_zenpage_news)) {
4232        $action .= '&title=' . urlencode($_zp_current_zenpage_news->getTitlelink());
4233      }
4234      break;
4235    case 'password.php':
4236      $action = str_replace(SEO_WEBPATH, '', getRequestURI());
4237      if ($action == '/' . _PAGE_ . '/password' || $action == '/index.php?p=password') {
4238        $action = '/index.php';
4239      }
4240      break;
4241    default:
4242      if (in_context(ZP_SEARCH)) {
4243        $action = '/index.php?userlog=1&p=search' . $_zp_current_search->getSearchParams();
4244      } else {
4245        $action = '/index.php?userlog=1&p=' . substr($_zp_gallery_page, 0, -4);
4246      }
4247  }
4248  return SEO_WEBPATH . $action;
4249}
4250
4251/**
4252 * Prints the album password form
4253 *
4254 * @param string $hint hint to the password
4255 * @param bool $showProtected set false to supress the password protected message
4256 * @param bool $showuser set true to force the user name filed to be present
4257 * @param string $redirect optional URL to send the user to after successful login
4258 *
4259 * @since 1.1.3
4260 */
4261function printPasswordForm($_password_hint, $_password_showuser = NULL, $_password_showProtected = true, $_password_redirect = NULL) {
4262	global $_zp_login_error, $_zp_password_form_printed, $_zp_current_search, $_zp_gallery, $_zp_gallery_page,
4263	$_zp_current_album, $_zp_current_image, $theme, $_zp_current_zenpage_page, $_zp_authority;
4264	if ($_zp_password_form_printed)
4265		return;
4266	$_zp_password_form_printed = true;
4267
4268	if (is_null($_password_redirect))
4269		$_password_redirect = getPageRedirect();
4270
4271	if (is_null($_password_showuser))
4272		$_password_showuser = $_zp_gallery->getUserLogonField();
4273	?>
4274	<div id="passwordform">
4275		<?php
4276			if(zp_loggedin()) {
4277				echo '<p><strong>' . gettext('You are successfully logged in.') . '</strong></p>';
4278			} else {
4279				if ($_password_showProtected && !$_zp_login_error) {
4280					?>
4281					<p>
4282						<?php echo gettext("The page you are trying to view is password protected."); ?>
4283					</p>
4284					<?php
4285				}
4286				if ($loginlink = zp_apply_filter('login_link', NULL)) {
4287					$logintext = gettext('login');
4288					?>
4289					<a href="<?php echo $loginlink; ?>" title="<?php echo $logintext; ?>"><?php echo $logintext; ?></a>
4290					<?php
4291				} else {
4292					$_zp_authority->printLoginForm($_password_redirect, false, $_password_showuser, false, $_password_hint);
4293				}
4294			}
4295		?>
4296	</div>
4297	<?php
4298}
4299
4300/**
4301 * prints the zenphoto logo and link
4302 *
4303 */
4304function printZenphotoLink() {
4305	echo gettext("Powered by <a href=\"http://www.zenphoto.org\" title=\"The simpler media website CMS\">Zenphoto</a>");
4306}
4307
4308/**
4309 * Expose some informations in a HTML comment
4310 *
4311 * @param string $obj the path to the page being loaded
4312 * @param array $plugins list of activated plugins
4313 * @param string $theme The theme being used
4314 */
4315function exposeZenPhotoInformations($obj = '', $plugins = '', $theme = '') {
4316	global $_zp_filters;
4317	$a = basename($obj);
4318	if ($a != 'full-image.php') {
4319		echo "\n<!-- zenphoto version " . ZENPHOTO_VERSION;
4320		if (TEST_RELEASE) {
4321			echo " THEME: " . $theme . " (" . $a . ")";
4322			$graphics = zp_graphicsLibInfo();
4323			$graphics = sanitize(str_replace('<br />', ', ', $graphics['Library_desc']), 3);
4324			echo " GRAPHICS LIB: " . $graphics . " { memory: " . INI_GET('memory_limit') . " }";
4325			echo ' PLUGINS: ';
4326			if (count($plugins) > 0) {
4327				sort($plugins);
4328				foreach ($plugins as $plugin) {
4329					echo $plugin . ' ';
4330				}
4331			} else {
4332				echo 'none ';
4333			}
4334		}
4335		echo " -->";
4336	}
4337}
4338
4339/**
4340 * Gets the content of a codeblock for an image, album or Zenpage newsarticle or page.
4341 *
4342 * The priority for codeblocks will be (based on context)
4343 * 	1: articles
4344 * 	2: pages
4345 * 	3: images
4346 * 	4: albums
4347 * 	5: gallery.
4348 *
4349 * This means, for instance, if we are in ZP_ZENPAGE_NEWS_ARTICLE context we will use the news article
4350 * codeblock even if others are available.
4351 *
4352 * Note: Echoing this array's content does not execute it. Also no special chars will be escaped.
4353 * Use printCodeblock() if you need to execute script code.
4354 *
4355 * @param int $number The codeblock you want to get
4356 * @param mixed $what optonal object for which you want the codeblock
4357 *
4358 * @return string
4359 */
4360function getCodeblock($number = 1, $object = NULL) {
4361	global $_zp_current_album, $_zp_current_image, $_zp_current_zenpage_news, $_zp_current_zenpage_page, $_zp_gallery, $_zp_gallery_page;
4362	if (!$number) {
4363		setOptionDefault('codeblock_first_tab', 0);
4364	}
4365	if (!is_object($object)) {
4366		if ($_zp_gallery_page == 'index.php') {
4367			$object = $_zp_gallery;
4368		}
4369		if (in_context(ZP_ALBUM)) {
4370			$object = $_zp_current_album;
4371		}
4372		if (in_context(ZP_IMAGE)) {
4373			$object = $_zp_current_image;
4374		}
4375		if (in_context(ZP_ZENPAGE_PAGE)) {
4376			if ($_zp_current_zenpage_page->checkAccess()) {
4377				$object = $_zp_current_zenpage_page;
4378			}
4379		}
4380		if (in_context(ZP_ZENPAGE_NEWS_ARTICLE)) {
4381			if ($_zp_current_zenpage_news->checkAccess()) {
4382				$object = $_zp_current_zenpage_news;
4383			}
4384		}
4385	}
4386	if (!is_object($object)) {
4387		return NULL;
4388	}
4389	$codeblock = getSerializedArray($object->getcodeblock());
4390	$codeblock = zp_apply_filter('codeblock', @$codeblock[$number], $object, $number);
4391	if ($codeblock) {
4392		$codeblock = applyMacros($codeblock);
4393	}
4394	return $codeblock;
4395}
4396
4397/**
4398 * Prints the content of a codeblock for an image, album or Zenpage newsarticle or page.
4399 *
4400 * @param int $number The codeblock you want to get
4401 * @param mixed $what optonal object for which you want the codeblock
4402 *
4403 * @return string
4404 */
4405function printCodeblock($number = 1, $what = NULL) {
4406	$codeblock = getCodeblock($number, $what);
4407	if ($codeblock) {
4408		$context = get_context();
4409		eval('?>' . $codeblock);
4410		set_context($context);
4411	}
4412}
4413
4414/**
4415 * Checks for URL page out-of-bounds for "standard" themes
4416 * Note: This function assumes that an "index" page will display albums
4417 * and the pagination be determined by them. Any other "index" page strategy needs to be
4418 * handled by the theme itself.
4419 *
4420 * @param boolean $request
4421 * @param string $gallery_page
4422 * @param int $page
4423 * @return boolean will be true if all is well, false if a 404 error should occur
4424 */
4425function checkPageValidity($request, $gallery_page, $page) {
4426	global $_zp_gallery, $_firstPageImages, $_oneImagePage, $_zp_zenpage, $_zp_current_category;
4427	$count = NULL;
4428	switch ($gallery_page) {
4429		case 'album.php':
4430		case 'search.php':
4431			$albums_per_page = max(1, getOption('albums_per_page'));
4432			$pageCount = (int) ceil(getNumAlbums() / $albums_per_page);
4433			$imageCount = getNumImages();
4434			if ($_oneImagePage) {
4435				if ($_oneImagePage === true) {
4436					$imageCount = min(1, $imageCount);
4437				} else {
4438					$imageCount = 0;
4439				}
4440			}
4441			$images_per_page = max(1, getOption('images_per_page'));
4442			$count = ($pageCount + (int) ceil(($imageCount - $_firstPageImages) / $images_per_page));
4443			break;
4444		case 'index.php':
4445			if (galleryAlbumsPerPage() != 0) {
4446				$count = (int) ceil($_zp_gallery->getNumAlbums() / galleryAlbumsPerPage());
4447			}
4448			break;
4449		case 'news.php':
4450			if (in_context(ZP_ZENPAGE_NEWS_CATEGORY)) {
4451				$count = count($_zp_current_category->getArticles());
4452			} else {
4453				$count = count($_zp_zenpage->getArticles());
4454			}
4455			$count = (int) ceil($count / ZP_ARTICLES_PER_PAGE);
4456			break;
4457		default:
4458			$count = zp_apply_filter('checkPageValidity', NULL, $gallery_page, $page);
4459			break;
4460	}
4461	if ($page > $count) {
4462		$request = false; //	page is out of range
4463	}
4464
4465	return $request;
4466}
4467
4468function print404status($album, $image, $obj) {
4469	global $_zp_page;
4470	echo "\n<strong>" . gettext("Zenphoto Error:</strong> the requested object was not found.");
4471	if (isset($album)) {
4472		echo '<br />' . sprintf(gettext('Album: %s'), html_encode($album));
4473
4474		if (isset($image)) {
4475			echo '<br />' . sprintf(gettext('Image: %s'), html_encode($image));
4476		}
4477	} else {
4478		echo '<br />' . sprintf(gettext('Page: %s'), html_encode(substr(basename($obj), 0, -4)));
4479	}
4480	if (isset($_zp_page) && $_zp_page > 1) {
4481		echo '/' . $_zp_page;
4482	}
4483}
4484
4485/**
4486 * Gets current item's owner (gallery images and albums) or author (Zenpage articles and pages)
4487 *
4488 * @since ZenphotoCMS 1.5.2
4489 *
4490 * @global obj $_zp_current_album
4491 * @global obj $_zp_current_image
4492 * @global obj $_zp_current_zenpage_page
4493 * @global obj $_zp_current_zenpage_news
4494 * @param boolean $fullname If the owner/author has a real user account and there is a full name set it is returned
4495 * @return boolean
4496 */
4497function getOwnerAuthor($fullname = false) {
4498	global $_zp_current_album, $_zp_current_image, $_zp_current_zenpage_page, $_zp_current_zenpage_news;
4499	$ownerauthor = false;
4500	if (in_context(ZP_IMAGE)) {
4501		$ownerauthor = $_zp_current_image->getOwner($fullname);
4502	} else if (in_context(ZP_ALBUM)) {
4503		$ownerauthor = $_zp_current_album->getOwner($fullname);
4504	}
4505	if (extensionEnabled('zenpage')) {
4506		if (is_Pages()) {
4507			$ownerauthor = $_zp_current_zenpage_page->getAuthor($fullname);
4508		} else if (is_NewsArticle()) {
4509			$ownerauthor = $_zp_current_zenpage_news->getAuthor($fullname);
4510		}
4511	}
4512	if ($ownerauthor) {
4513		return $ownerauthor;
4514	}
4515	return false;
4516}
4517
4518/**
4519 * Prints current item's owner (gallery images and albums) or author (Zenpage articles and pages)
4520 *
4521 * @since ZenphotoCMS 1.5.2
4522 *
4523 * @param type $fullname
4524 */
4525function printOwnerAuthor($fullname = false) {
4526	echo html_encode(getOwnerAuthor($fullname));
4527}
4528
4529/**
4530 * Returns the search url for items the current item's owner (gallery) or author (Zenpage) is assigned to
4531 *
4532 * This eventually may return the url to an actual user profile page in the future.
4533 *
4534 * @since ZenphotoCMS 1.5.2
4535 *
4536 * @return type
4537 */
4538function getOwnerAuthorURL() {
4539	$ownerauthor = getOwnerAuthor(false);
4540	if($ownerauthor) {
4541		if (in_context(ZP_IMAGE) || in_context(ZP_ALBUM)) {
4542			return getUserURL($ownerauthor, 'gallery');
4543		}
4544		if (extensionEnable('zenpagae') && (is_Pages() || is_NewsArticle())) {
4545			return getUserURL($ownerauthor, 'zenpage');
4546		}
4547	}
4548}
4549
4550/**
4551 * Prints the link to the search engine for results of all items the current item's owner (gallery) or author (Zenpage) is assigned to
4552 *
4553 * This eventually may return the url to an actual user profile page in the future.
4554 *
4555 * @since ZenphotoCMS 1.5.2
4556 *
4557 * @param type $fullname
4558 * @param type $resulttype
4559 * @param type $class
4560 * @param type $id
4561 * @param type $title
4562 */
4563function printOwnerAuthorURL($fullname = false, $resulttype = 'all', $class = null, $id = null, $title = null) {
4564	$author = $linktext = $title = getOwnerAuthor(false);
4565	if ($author) {
4566		if ($fullname) {
4567			$linktext = getOwnerAuthor(true);
4568		}
4569		if(is_null($title)) {
4570			$title = $linktext;
4571		}
4572		printUserURL($author, $resulttype, $linktext, $class, $id, $title);
4573	}
4574}
4575
4576/**
4577 * Returns a an url for the search engine for results of all items the user with $username is assigned to either as owner (gallery) or author (Zenpage)
4578 *  Note there is no check if the user name is actually a vaild user account name, owner or author! Use the *OwerAuthor() function for that instead
4579 *
4580 * This eventually may return the url to an actual user profile page in the future.
4581 *
4582 * @since ZenphotoCMS 1.5.2
4583 *
4584 * @param string $username The user name of a user. Note there is no check if the user name is actually valid!
4585 * @param string $resulttype  'all' for owner and author, 'gallery' for owner of images/albums only, 'zenpage' for author of news articles and pages
4586 * @return string|null
4587 */
4588function getUserURL($username, $resulttype = 'all') {
4589	if (empty($username)) {
4590		return null;
4591	}
4592	switch ($resulttype) {
4593		case 'all':
4594		default:
4595			$fields = array('owner', 'author');
4596			break;
4597		case 'gallery':
4598			$fields = array('owner');
4599			break;
4600		case 'zenpage':
4601			$fields = array('author');
4602			break;
4603	}
4604	return getSearchURL(search_quote($username), '', $fields, 1, null);
4605}
4606
4607/**
4608 * Prints the link to the search engine for results of all items $username is assigned to either as owner (gallery) or author (Zenpage)
4609 * Note there is no check if the user name is actually a vaild user account name, owner or author! Use the *OwerAuthor() function for that instead
4610 *
4611 * This eventually may point to an actual user profile page in the future.
4612 *
4613 * @since ZenphotoCMS 1.5.2
4614 *
4615 * @param string $username The user name of a user.
4616 * @param string $resulttype  'all' for owner and author, 'gallery' for owner of images/albums only, 'zenpage' for author of news articles and pages
4617 * @param string $linktext The link text. If null the user name will be used
4618 * @param string $class The CSS class to attach, default null.
4619 * @param type $id The CSS id to attach, default null.
4620 * @param type $title The title attribute to attach, default null so the user name is used
4621 */
4622function printUserURL($username, $resulttype = 'all', $linktext = null, $class = null, $id = null, $title = null) {
4623	if ($username) {
4624		$url = getUserURL($username, $resulttype);
4625		if (is_null($linktext)) {
4626			$linktext = $username;
4627		}
4628		if (is_null($title)) {
4629			$title = $username;
4630		}
4631		printLinkHTML($url, $linktext, $title, $class, $id);
4632	}
4633}
4634
4635/**
4636 * Display the site copyright notice if defined and display is enabled
4637 *
4638 * @since ZenphotoCMS 1.5.8
4639 *
4640 * @global obj $_zp_gallery
4641 * @param string $before Text to print before it
4642 * @param string $after Text to print after it
4643 */
4644function printCopyrightNotice($before = '', $after = '') {
4645	global $_zp_gallery;
4646	$copyright_notice = $_zp_gallery->getCopyrightNotice();
4647	if(!empty($copyright_notice) && getOption('display_copyright_notice')) {
4648		echo $before . $copyright_notice . $after;
4649	}
4650}
4651
4652require_once(SERVERPATH . '/' . ZENFOLDER . '/template-filters.php');
4653?>
4654