PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/singapore.class.php

https://github.com/zhangweiwu/singapore
PHP | 980 lines | 590 code | 141 blank | 249 comment | 125 complexity | 0e5ef3cbfa7377ea75311c8d1dd71072 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * Main class.
  4. * @license http://opensource.org/licenses/gpl-license.php GNU General Public License
  5. * @copyright (c)2003-2006 Tamlyn Rhodes
  6. * @version $Id: singapore.class.php,v 1.80 2010/09/01 00:33:13 zhangweiwu Exp $
  7. */
  8. //define constants for regular expressions
  9. define('SG_REGEXP_PROTOCOLURL', '(?:http://|https://|ftp://|mailto:)(?:[a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,4}(?::[0-9]+)?(?:/[^ \n\r\"\'<]+)?');
  10. define('SG_REGEXP_WWWURL', 'www\.(?:[a-zA-Z0-9\-]+\.)*[a-zA-Z]{2,4}(?:/[^ \n\r\"\'<]+)?');
  11. define('SG_REGEXP_EMAILURL', '(?:[\w][\w\.\-]+)+@(?:[\w\-]+\.)+[a-zA-Z]{2,4}');
  12. /**
  13. * Provides functions for handling galleries and images
  14. * @package singapore
  15. * @author Tamlyn Rhodes <tam at zenology dot co dot uk>
  16. */
  17. class Singapore
  18. {
  19. /**
  20. * current script version
  21. * @var string
  22. */
  23. var $version = "0.10.1";
  24. /**
  25. * instance of a {@link sgConfig} object representing the current
  26. * script configuration
  27. * @var sgConfig
  28. */
  29. var $config;
  30. /**
  31. * instance of the currently selected IO handler object
  32. * @var sgIO_csv
  33. */
  34. var $io;
  35. /**
  36. * instance of a {@link Translator}
  37. * @var Translator
  38. */
  39. var $translator;
  40. /**
  41. * instance of a {@link sgGallery} representing the current gallery
  42. * @var sgGallery
  43. */
  44. var $gallery;
  45. /**
  46. * reference to the currently selected {@link sgImage} object in the
  47. * $images array of {@link $gallery}
  48. * @var sgImage
  49. */
  50. var $image;
  51. /**
  52. * two character code of language currently in use
  53. * @var string
  54. */
  55. var $language = null;
  56. /**
  57. * name of template currently in use
  58. * @var string
  59. */
  60. var $template = null;
  61. /**
  62. * details of current user
  63. * @var sgUser
  64. */
  65. var $user = null;
  66. /**
  67. * name of action requested
  68. * @var string
  69. */
  70. var $action = null;
  71. /**
  72. * Constructor, does all init type stuff. This code is a total mess.
  73. * @param string the path to the base singapore directory
  74. */
  75. function Singapore($basePath = "")
  76. {
  77. //import class definitions
  78. //io handler class included once config is loaded
  79. require_once $basePath."includes/translator.class.php";
  80. require_once $basePath."includes/thumbnail.class.php";
  81. require_once $basePath."includes/gallery.class.php";
  82. require_once $basePath."includes/config.class.php";
  83. require_once $basePath."includes/image.class.php";
  84. require_once $basePath."includes/user.class.php";
  85. //start execution timer
  86. $this->scriptStartTime = microtime();
  87. //remove slashes
  88. if(get_magic_quotes_gpc())
  89. $_REQUEST = array_map(array("Singapore","arraystripslashes"), $_REQUEST);
  90. //desanitize request
  91. $_REQUEST = array_map("htmlentities", $_REQUEST);
  92. //load config from singapore root directory
  93. $this->config = sgConfig::getInstance();
  94. $this->config->loadConfig($basePath."singapore.ini");
  95. $this->config->loadConfig($basePath."secret.ini.php");
  96. //if instantiated remotely...
  97. if(!empty($basePath)) {
  98. //...try to guess base path and relative url
  99. if(empty($this->config->base_path))
  100. $this->config->base_path = $basePath;
  101. if(empty($this->config->base_url))
  102. $this->config->base_url = $basePath;
  103. //...load local config if present
  104. //may over-ride guessed values above
  105. $this->config->loadConfig("singapore.local.ini");
  106. }
  107. //set current gallery to root if not specified in url
  108. $galleryId = isset($_GET[$this->config->url_gallery]) ? $_GET[$this->config->url_gallery] : ".";
  109. //load config from gallery ini file (gallery.ini) if present
  110. $this->config->loadConfig($basePath.$this->config->pathto_galleries.$galleryId."/gallery.ini");
  111. //set current template from request vars or config
  112. //first, preset template to default one
  113. $this->template = $this->config->default_template;
  114. //then check if requested template exists
  115. if(!empty($_REQUEST[$this->config->url_template])) {
  116. $templates = Singapore::getListing($this->config->base_path.$this->config->pathto_templates);
  117. foreach($templates->dirs as $single) {
  118. if($single == $_REQUEST[$this->config->url_template]) {
  119. $this->template = $single;
  120. break;
  121. }
  122. }
  123. }
  124. $this->config->pathto_current_template = $this->config->pathto_templates.$this->template.'/';
  125. //load config from template ini file (template.ini) if present
  126. $this->config->loadConfig($basePath.$this->config->pathto_current_template."template.ini");
  127. //set runtime values
  128. $this->config->pathto_logs = $this->config->pathto_data_dir."logs/";
  129. $this->config->pathto_cache = $this->config->pathto_data_dir."cache/";
  130. $this->config->pathto_admin_template = $this->config->pathto_templates.$this->config->admin_template_name."/";
  131. //set current language from request vars or config
  132. if(!empty($_REQUEST[$this->config->url_lang]))
  133. $this->language = $_REQUEST[$this->config->url_lang];
  134. else {
  135. $this->language = $this->config->default_language;
  136. if($this->config->detect_language)
  137. foreach($this->getBrowserLanguages() as $lang)
  138. if($lang=="en" || file_exists($basePath.$this->config->pathto_locale."singapore.".$lang.".pmo")) {
  139. $this->language = $lang;
  140. break;
  141. }
  142. }
  143. //read the language file
  144. $this->translator = Translator::getInstance($this->language);
  145. $this->translator->readLanguageFile($this->config->base_path.$this->config->pathto_locale."singapore.".$this->language.".pmo");
  146. //clear the UMASK
  147. umask(0);
  148. //include IO handler class and create instance
  149. require_once $basePath."includes/io_".$this->config->io_handler.".class.php";
  150. $ioClassName = "sgIO_".$this->config->io_handler;
  151. $this->io = new $ioClassName($this->config);
  152. //load gallery and image info
  153. $this->selectGallery($galleryId);
  154. //set character set
  155. if(!empty($this->translator->languageStrings[0]["charset"]))
  156. $this->character_set = $this->translator->languageStrings[0]["charset"];
  157. else
  158. $this->character_set = $this->config->default_charset;
  159. if (ini_get("mbstring.func_overload") == "7") {
  160. $this->character_set = "UTF-8";
  161. }
  162. //set action to perform
  163. if(empty($_REQUEST["action"])) $this->action = "view";
  164. else $this->action = $_REQUEST["action"];
  165. }
  166. /**
  167. * Load gallery and image info
  168. * @param string the id of the gallery to load (optional)
  169. */
  170. function selectGallery($galleryId = "")
  171. {
  172. if(empty($galleryId)) $galleryId = isset($_REQUEST[$this->config->url_gallery]) ? $_REQUEST[$this->config->url_gallery] : ".";
  173. //try to validate gallery id
  174. if(strlen($galleryId)>1 && $galleryId{1} != '/') $galleryId = './'.$galleryId;
  175. //detect back-references to avoid file-system walking
  176. if(strpos($galleryId,"../")!==false) $galleryId = ".";
  177. //find all ancestors to current gallery
  178. $this->ancestors = array();
  179. $ancestorNames = explode("/", $galleryId);
  180. $numberOfAncestors = count($ancestorNames);
  181. //construct fully qualified gallery ids
  182. $ancestorIds[0] = ".";
  183. for($i=1; $i<$numberOfAncestors; $i++)
  184. $ancestorIds[$i] = $ancestorIds[$i-1]."/".$ancestorNames[$i];
  185. //fetch galleries passing previous gallery as parent pointer
  186. for($i=0; $i<$numberOfAncestors; $i++)
  187. if(!$this->ancestors[$i] = $this->io->getGallery(
  188. $ancestorIds[$i], $this->ancestors[$i-1],
  189. //only fetch children of bottom level gallery
  190. ($i==$numberOfAncestors-1) ? 1 : 0
  191. )
  192. )
  193. break;
  194. //need to remove bogus parent of root gallery created by previous step
  195. unset($this->ancestors[-1]);
  196. //set reference to current gallery
  197. $this->gallery = &$this->ancestors[count($this->ancestors)-1];
  198. //check if gallery was successfully fetched
  199. if($this->gallery == null) {
  200. $this->gallery = new sgGallery($galleryId, $this->ancestors[0]);
  201. $this->gallery->name = $this->translator->_g("Gallery not found '%s'",htmlspecialchars($galleryId));
  202. }
  203. //sort galleries and images
  204. $GLOBALS["sgSortOrder"] = $this->config->gallery_sort_order;
  205. if($this->config->gallery_sort_order!="x") usort($this->gallery->galleries, array("Singapore","multiSort"));
  206. $GLOBALS["sgSortOrder"] = $this->config->image_sort_order;
  207. if($this->config->image_sort_order!="x") usort($this->gallery->images, array("Singapore","multiSort"));
  208. unset($GLOBALS["sgSortOrder"]);
  209. //if startat is set then cast to int otherwise startat 0
  210. $this->gallery->startat = isset($_REQUEST[$this->config->url_startat]) ? (int)$_REQUEST[$this->config->url_startat] : 0;
  211. $this->startat = $this->gallery->startat; //depreciated
  212. //select the image (if any)
  213. if(!empty($_REQUEST[$this->config->url_image]))
  214. $this->selectImage($_REQUEST[$this->config->url_image]);
  215. //load hit data
  216. if($this->config->track_views || $this->config->show_views)
  217. $this->io->getHits($this->gallery);
  218. //update and save hit data
  219. if($this->config->track_views) {
  220. if($this->isImagePage()) {
  221. $this->image->hits++;
  222. $this->image->lasthit = time();
  223. } elseif($this->gallery->startat == 0) {
  224. $this->gallery->hits++;
  225. $this->gallery->lasthit = time();
  226. }
  227. $this->io->putHits($this->gallery);
  228. }
  229. }
  230. /**
  231. * Selects an image from the current gallery
  232. * @param mixed either the filename of the image to select or the integer
  233. * index of its position in the images array
  234. * @return boolean true on success; false otherwise
  235. */
  236. function selectImage($image)
  237. {
  238. if(is_string($image)) {
  239. foreach($this->gallery->images as $index => $img)
  240. if($img->id == $image) {
  241. $this->image = $this->gallery->images[$index];
  242. return true;
  243. }
  244. } elseif(is_int($image) && $image >= 0 && $image < count($this->gallery->images)) {
  245. $this->image = $this->gallery->images[$image];
  246. return true;
  247. }
  248. $this->image = new sgImage("", $this->gallery);
  249. $this->image->name = $this->translator->_g("Image not found '%s'",htmlspecialchars($image));
  250. return false;
  251. }
  252. /**
  253. * Obfuscates the given email address by replacing "." with "dot" and "@" with "at"
  254. * @param string email address to obfuscate
  255. * @param boolean override the obfuscate_email config setting (optional)
  256. * @return string obfuscated email address or HTML mailto link
  257. */
  258. function formatEmail($email, $forceObfuscate = false)
  259. {
  260. if($this->config->obfuscate_email || $forceObfuscate)
  261. return strtr($email,array("@" => ' <b>'.$this->translator->_g("email|at").'</b> ', "." => ' <b>'.$this->translator->_g("email|dot").'</b> '));
  262. else
  263. return "<a href=\"mailto:".$email."\">".$email."</a>";
  264. }
  265. /**
  266. * Returns image name for image pages and gallery name for gallery pages.
  267. * If either of these is empty, returns gallery_name config option.
  268. *
  269. * @return string Title of current page
  270. */
  271. function pageTitle()
  272. {
  273. $crumbArray = $this->crumbLineArray();
  274. $ret = "";
  275. for($i=count($crumbArray)-1;$i>0;$i--)
  276. $ret .= $crumbArray[$i]->nameForce()." &lt; ";
  277. $ret .= $crumbArray[$i]->nameForce();
  278. return $ret;
  279. }
  280. /**
  281. * @return bool true if this is an image page; false otherwise
  282. */
  283. function isImagePage()
  284. {
  285. return !empty($this->image);
  286. }
  287. /**
  288. * @return bool true if this is a non-album gallery page; false otherwise
  289. */
  290. function isGalleryPage()
  291. {
  292. return !empty($this->gallery) && $this->gallery->galleryCount()>0;;
  293. }
  294. /**
  295. * @return bool true if this is an album page; false otherwise
  296. */
  297. function isAlbumPage()
  298. {
  299. return !$this->isGalleryPage() && !$this->isImagePage() && !empty($this->gallery);
  300. }
  301. /**
  302. * @return int the script execution time in seconds rounded to two decimal places
  303. */
  304. function scriptExecTime()
  305. {
  306. $scriptStartTime = $this->scriptStartTime;
  307. $scriptEndTime = microtime();
  308. list($usec, $sec) = explode(" ",$scriptStartTime);
  309. $scriptStartTime = (float)$usec + (float)$sec;
  310. list($usec, $sec) = explode(" ",$scriptEndTime);
  311. $scriptEndTime = (float)$usec + (float)$sec;
  312. $scriptExecTime = floor(($scriptEndTime - $scriptStartTime)*100)/100;
  313. return $scriptExecTime;
  314. }
  315. /**
  316. * Displays the script execution time if configured to do so
  317. * @returns string the script execution time
  318. */
  319. function scriptExecTimeText()
  320. {
  321. if($this->config->show_execution_time)
  322. return $this->translator->_g("Page created in %s seconds",$this->scriptExecTime());
  323. else
  324. return "";
  325. }
  326. function poweredByText()
  327. {
  328. return $this->translator->_g("Powered by").' <a href="http://www.sgal.org/">singapore</a>';
  329. }
  330. function allRightsReserved()
  331. {
  332. return $this->translator->_g("All rights reserved.");
  333. }
  334. function licenseText()
  335. {
  336. return $this->translator->_g("Images may not be reproduced in any form without the express written permission of the copyright holder.");
  337. }
  338. function adminURL()
  339. {
  340. return '<a href="'.$this->config->base_url.'admin.php">';
  341. }
  342. function adminLink()
  343. {
  344. return $this->adminURL().$this->translator->_g("Log in")."</a>";
  345. }
  346. /**
  347. * Checks to see if the user is currently logged in to admin mode. Also resets
  348. * the login timeout to the current time.
  349. * @returns boolean true if the user is logged in; false otherwise
  350. * @static
  351. */
  352. function isLoggedIn()
  353. {
  354. if(
  355. isset($this->user) &&
  356. $_SESSION["sgUser"]["ip"] == $_SERVER["REMOTE_ADDR"] &&
  357. (time() - $_SESSION["sgUser"]["loginTime"] < 600)
  358. ) {
  359. //reset loginTime to current time
  360. $_SESSION["sgUser"]["loginTime"] = time();
  361. return true;
  362. }
  363. return false;
  364. }
  365. function loadUser($username = null)
  366. {
  367. if($username == null)
  368. if(isset($_SESSION["sgUser"]))
  369. $username = $_SESSION["sgUser"]["username"];
  370. else
  371. return false;
  372. $users = $this->io->getUsers();
  373. foreach($users as $user)
  374. if($user->username == $username) {
  375. $this->user = $user;
  376. return $user;
  377. }
  378. return false;
  379. }
  380. /**
  381. * Creates an array of objects each representing an item in the crumb line.
  382. * @return array the items of the crumb line
  383. */
  384. function crumbLineArray()
  385. {
  386. $crumb = $this->ancestors;
  387. if($this->isImagePage()) $crumb[] = $this->image;
  388. return $crumb;
  389. }
  390. /**
  391. * @return string the complete crumb line with links
  392. */
  393. function crumbLineText()
  394. {
  395. $crumbArray = $this->crumbLineArray();
  396. $ret = "";
  397. for($i=0;$i<count($crumbArray)-1;$i++)
  398. $ret .= $crumbArray[$i]->nameLink()." &gt;\n";
  399. $ret .= $crumbArray[$i]->nameForce();
  400. return $ret;
  401. }
  402. function crumbLine()
  403. {
  404. return $this->translator->_g("crumb line|You are here:")." ".$this->crumbLineText();
  405. }
  406. /**
  407. * Generates the HTML code for imagemap_navigation
  408. * @return string imagemap HTML code
  409. */
  410. function imageMap()
  411. {
  412. if(!$this->config->imagemap_navigation) return "";
  413. $imageWidth = $this->image->width();
  414. $imageHeight = $this->image->height();
  415. $middleX = round($imageWidth/2);
  416. $middleY = round($imageHeight/2);
  417. $ret = "<map name=\"sgNavMap\" id=\"sgNavMap\">\n";
  418. if($this->image->hasNext()) $ret .= '<area href="'.$this->image->nextURL().'" alt="'.$this->image->nextText().'" title="'.$this->image->nextText().'" shape="poly" ';
  419. else $ret .= '<area href="'.$this->image->parentURL().'" alt="'.$this->image->parentText().'" title="'.$this->image->parentText().'" shape="poly" ';
  420. $ret .= "coords=\"$middleX,$middleY,$imageWidth,$imageHeight,$imageWidth,0,$middleX,$middleY\" />\n";
  421. if($this->image->hasPrev()) $ret .= '<area href="'.$this->image->prevURL().'" alt="'.$this->image->prevText().'" title="'.$this->image->prevText().'" shape="poly" ';
  422. else $ret .= '<area href="'.$this->image->parentURL().'" alt="'.$this->image->parentText().'" title="'.$this->image->parentText().'" shape="poly" ';
  423. $ret .= "coords=\"$middleX,$middleY,0,0,0,$imageHeight,$middleX,$middleY\" />\n";
  424. $ret .= '<area href="'.$this->image->parentURL().'" alt="'.$this->image->parentText().'" title="'.$this->image->parentText().'" shape="poly" ';
  425. $ret .= "coords=\"$middleX,$middleY,0,0,$imageWidth,0,$middleX,$middleY\" />\n";
  426. $ret .= '</map>';
  427. return $ret;
  428. }
  429. /**
  430. * Generates the HTML code for the language select box
  431. * @return string select box HTML code
  432. */
  433. function languageFlipper()
  434. {
  435. if(!$this->config->language_flipper) return "";
  436. $languageCache = $this->config->base_path.$this->config->pathto_data_dir."languages.cache";
  437. // Look for the language file
  438. if(!file_exists($languageCache))
  439. return "";
  440. // Open the file
  441. $fp = @fopen($languageCache, "r");
  442. if (!$fp) return "";
  443. // Read contents
  444. $str = '';
  445. while (!feof($fp)) $str .= fread($fp, 1024);
  446. // Unserialize
  447. $availableLanguages = @unserialize($str);
  448. $ret = '<div class="sgLanguageFlipper">';
  449. $ret .= '<form method="get" action="'.$_SERVER["PHP_SELF"]."\">\n";
  450. //carry over current get vars
  451. foreach($_GET as $var => $val)
  452. $ret .= '<input type="hidden" name="'.$var.'" value="'.htmlspecialchars($val)."\" />\n";
  453. $ret .= '<select name="'.$this->config->url_lang."\">\n";
  454. $ret .= ' <option value="'.$this->config->default_language.'">'.$this->translator->_g("Select language...")."</option>\n";
  455. foreach($availableLanguages as $code => $name) {
  456. $ret .= ' <option value="'.$code.'"';
  457. if($code == $this->language && $this->language != $this->config->default_language)
  458. $ret .= 'selected="true" ';
  459. $ret .= '>'.htmlentities($name)."</option>\n";
  460. }
  461. $ret .= "</select>\n";
  462. $ret .= '<input type="submit" class="button" value="'.$this->translator->_g("Go")."\" />\n";
  463. $ret .= "</form></div>\n";
  464. return $ret;
  465. }
  466. /**
  467. * Generates the HTML code for the template select box
  468. * @return string select box HTML code
  469. */
  470. function templateFlipper()
  471. {
  472. if(!$this->config->template_flipper) return "";
  473. //get list of installed templates
  474. $templates = Singapore::getListing($this->config->base_path.$this->config->pathto_templates, "dirs");
  475. $ret = '<div class="sgTemplateFlipper">';
  476. $ret .= '<form method="get" action="'.$_SERVER["PHP_SELF"]."\">\n";
  477. //carry over current get vars
  478. foreach($_GET as $var => $val)
  479. $ret .= '<input type="hidden" name="'.$var.'" value="'.htmlspecialchars($val)."\" />\n";
  480. $ret .= '<select name="'.$this->config->url_template."\">\n";
  481. $ret .= ' <option value="'.$this->config->default_template.'">'.$this->translator->_g("Select template...")."</option>\n";
  482. foreach($templates->dirs as $name)
  483. //do not list admin template(s)
  484. if(strpos($name, "admin_")===false) {
  485. $ret .= ' <option value="'.$name.'"';
  486. if($name == $this->template && $this->template != $this->config->default_template)
  487. $ret .= 'selected="true" ';
  488. $ret .= '>'.$name."</option>\n";
  489. }
  490. $ret .= "</select>\n";
  491. $ret .= '<input type="submit" class="button" value="'.$this->translator->_g("Go")."\" />\n";
  492. $ret .= "</form></div>\n";
  493. return $ret;
  494. }
  495. /**
  496. * @param string $seperator optional string to seperate the Gallery Tab Links
  497. * @return string
  498. */
  499. function galleryTab($seperator = " | ")
  500. {
  501. $showing = $this->galleryTabShowing();
  502. return Singapore::conditional($this->galleryTabLinks(), $showing.$seperator."%s", $showing);
  503. }
  504. /**
  505. * @return string
  506. */
  507. function galleryTabShowing()
  508. {
  509. if($this->isAlbumPage()) {
  510. $total = $this->gallery->imageCount();
  511. $perPage = $this->config->thumb_number_album;
  512. } else {
  513. $total = $this->gallery->galleryCount();
  514. $perPage = $this->config->thumb_number_gallery;
  515. }
  516. if($this->gallery->startat+$perPage > $total)
  517. $last = $total;
  518. else
  519. $last = $this->gallery->startat+$perPage;
  520. return $this->translator->_g("Showing %s-%s of %s",($this->gallery->startat+1),$last,$total);
  521. }
  522. /**
  523. * @return string
  524. */
  525. function galleryTabLinks()
  526. {
  527. $ret = "";
  528. if($this->hasPrevPage())
  529. $ret .= $this->prevPageLink()." ";
  530. //This is for compatibility with old templates
  531. //it detects if compatibility mode is on using method_exists()
  532. if(!$this->gallery->isRoot() && method_exists($this, 'galleryName'))
  533. $ret .= $this->gallery->parentLink();
  534. if($this->hasNextPage())
  535. $ret .= " ".$this->nextPageLink();
  536. return $ret;
  537. }
  538. function navigationLinks() {
  539. $ret = "<link rel=\"Top\" title=\"".$this->config->gallery_name."\" href=\"".$this->ancestors[0]->URL()."\" />\n";
  540. if($this->isImagePage()) {
  541. $ret .= "<link rel=\"Up\" title=\"".$this->image->parent->name()."\" href=\"".$this->image->parent->URL()."\" />\n";
  542. if ($this->image->hasPrev()) {
  543. $first= $this->image->firstImage();
  544. $prev = $this->image->prevImage();
  545. $ret .= "<link rel=\"First\" title=\"".$first->name()."\" href=\"".$first->URL()."\" />\n";
  546. $ret .= "<link rel=\"Prev\" title=\"".$prev->name()."\" href=\"".$prev->URL()."\" />\n";
  547. }
  548. if ($this->image->hasNext()) {
  549. $next = $this->image->nextImage();
  550. $last = $this->image->lastImage();
  551. $ret .= "<link rel=\"Next\" title=\"".$next->name()."\" href=\"".$next->URL()."\" />\n";
  552. $ret .= "<link rel=\"Last\" title=\"".$last->name()."\" href=\"".$last->URL()."\" />\n";
  553. //prefetch next image
  554. $ret .= "<link rel=\"Prefetch\" href=\"".$next->imageURL()."\" />\n";
  555. }
  556. } else {
  557. if(!$this->gallery->isRoot())
  558. $ret .= "<link rel=\"Up\" title=\"".$this->gallery->parent->name()."\" href=\"".$this->gallery->parent->URL()."\" />\n";
  559. if($this->hasPrevPage()) {
  560. $ret .= "<link rel=\"Prev\" title=\"".$this->translator->_g("gallery|Previous")."\" href=\"".$this->prevPageURL()."\" />\n";
  561. $ret .= "<link rel=\"First\" title=\"".$this->translator->_g("gallery|First")."\" href=\"".$this->firstPageURL()."\" />\n";
  562. }
  563. if($this->hasNextPage()) {
  564. $ret .= "<link rel=\"Next\" title=\"".$this->translator->_g("gallery|Next")."\" href=\"".$this->nextPageURL()."\" />\n";
  565. $ret .= "<link rel=\"Last\" title=\"".$this->translator->_g("gallery|Last")."\" href=\"".$this->lastPageURL()."\" />\n";
  566. }
  567. }
  568. return $ret;
  569. }
  570. /**
  571. * @return int the number of 'pages' or 'screen-fulls'
  572. */
  573. function galleryPageCount() {
  574. if($this->isAlbumPage())
  575. return intval($this->gallery->imageCount()/$this->config->thumb_number_album)+1;
  576. else
  577. return intval($this->gallery->galleryCount()/$this->config->thumb_number_gallery)+1;
  578. }
  579. /**
  580. * @return int
  581. */
  582. function lastPageIndex() {
  583. if($this->isAlbumPage())
  584. return ($this->galleryPageCount()-1)*
  585. ($this->isAlbumPage()?$this->config->thumb_number_album:$this->config->thumb_number_gallery);
  586. }
  587. /**
  588. * @return bool true if there is at least one more page
  589. */
  590. function hasNextPage() {
  591. if($this->isAlbumPage())
  592. return count($this->gallery->images)>$this->startat+$this->config->thumb_number_album;
  593. elseif($this->isGalleryPage())
  594. return count($this->gallery->galleries)>$this->startat+$this->config->thumb_number_gallery;
  595. elseif($this->isImagePage())
  596. return isset($this->gallery->images[$this->image->index+1]);
  597. }
  598. /**
  599. * @return bool true if there is at least one previous page
  600. */
  601. function hasPrevPage() {
  602. if($this->isAlbumPage() || $this->isGalleryPage())
  603. return $this->startat > 0;
  604. elseif($this->isImagePage())
  605. return isset($this->gallery->images[$this->image->index-1]);
  606. }
  607. function firstPageURL() {
  608. return $this->gallery->URL(0);
  609. }
  610. function firstPageLink() {
  611. return "<a href=\"".$this->firstPageURL()."\">".$this->translator->_g("First %s", $this->itemsPerPage())."</a>";
  612. }
  613. /**
  614. * @return string the URL of the previous page
  615. */
  616. function prevPageURL() {
  617. return $this->gallery->URL($this->startat - $this->itemsPerPage());
  618. }
  619. function prevPageLink() {
  620. return "<a href=\"".$this->prevPageURL()."\">".$this->translator->_g("Previous %s", $this->itemsPerPage())."</a>";
  621. }
  622. /**
  623. * @return string the URL of the next page
  624. */
  625. function nextPageURL() {
  626. return $this->gallery->URL($this->startat + $this->itemsPerPage());
  627. }
  628. function nextPageLink() {
  629. return "<a href=\"".$this->nextPageURL()."\">".$this->translator->_g("Next %s", $this->itemsPerPage())."</a>";
  630. }
  631. function lastPageURL() {
  632. $perpage = $this->isAlbumPage() ? $this->config->thumb_number_album : $this->config->thumb_number_gallery;
  633. return $this->gallery->URL(floor($this->gallery->itemCount() / $perpage) * $perpage);
  634. }
  635. function lastPageLink() {
  636. return "<a href=\"".$this->lastPageURL()."\">".$this->translator->_g("Last %s", $this->itemsPerPage())."</a>";
  637. }
  638. function itemsPerPage()
  639. {
  640. return $this->isAlbumPage() ? $this->config->thumb_number_album : $this->config->thumb_number_gallery;
  641. }
  642. /**
  643. * @return string link for adding a comment to image
  644. */
  645. function imageCommentLink()
  646. {
  647. return "<a href=\"".
  648. $this->formatURL($this->gallery->idEncoded(), $this->image->id, null, "addcomment").
  649. "\">".$this->translator->_g("Add a comment")."</a>";
  650. }
  651. /**
  652. * @return array array of sgImage objects
  653. */
  654. function &previewThumbnailsArray()
  655. {
  656. $ret = array();
  657. $index = $this->image->index();
  658. $start = ceil($index - $this->config->thumb_number_preview/2);
  659. for($i = $start; $i < $start + $this->config->thumb_number_preview; $i++)
  660. if(isset($this->image->parent->images[$i]))
  661. $ret[$i] = $this->image->parent->images[$i];
  662. return $ret;
  663. }
  664. function previewThumbnails()
  665. {
  666. $thumbs = $this->previewThumbnailsArray();
  667. $index = $this->image->index();
  668. $ret = "";
  669. foreach($thumbs as $key => $thumb) {
  670. $thumbClass = "sgThumbnailPreview";
  671. if($key==$index-1) $thumbClass .= " sgThumbnailPreviewPrev";
  672. elseif($key==$index) $thumbClass .= " sgThumbnailPreviewCurrent";
  673. elseif($key==$index+1) $thumbClass .= " sgThumbnailPreviewNext";
  674. $ret .= $thumb->thumbnailLink($thumbClass, "preview")."\n";
  675. }
  676. return $ret;
  677. }
  678. //////////////////////////////
  679. //////ex-sgUtils methods//////
  680. //////////////////////////////
  681. /**
  682. * Callback function for sorting things
  683. * @static
  684. */
  685. function multiSort($a, $b) {
  686. switch($GLOBALS["sgSortOrder"]) {
  687. case "f" :
  688. case "p" : return strcmp($a->id, $b->id); //path
  689. case "F" :
  690. case "P" : return strcmp($b->id, $a->id); //path (reverse)
  691. case "n" : return strcmp($a->name, $b->name); //name
  692. case "N" : return strcmp($b->name, $a->name); //name (reverse)
  693. case "i" : return strcasecmp($a->name, $b->name); //case-insensitive name
  694. case "I" : return strcasecmp($b->name, $a->name); //case-insensitive name (reverse)
  695. case "a" : return strcmp($a->artist, $b->artist); //artist
  696. case "A" : return strcmp($b->artist, $a->artist); //artist (reverse)
  697. case "d" : return strcmp($a->date, $b->date); //date
  698. case "D" : return strcmp($b->date, $a->date); //date (reverse)
  699. case "l" : return strcmp($a->location, $b->location); //location
  700. case "L" : return strcmp($b->location, $a->location); //location (reverse)
  701. }
  702. }
  703. /**
  704. * Slightly pointless method
  705. */
  706. function conditional($conditional, $iftrue, $iffalse = null)
  707. {
  708. if($conditional) return sprintf($iftrue, $conditional);
  709. elseif($iffalse != null) return sprintf($iffalse, $conditional);
  710. else return "";
  711. }
  712. /**
  713. * Callback function for recursively stripping slashes
  714. * @static
  715. */
  716. function arraystripslashes($toStrip)
  717. {
  718. if(is_array($toStrip))
  719. return array_map(array("Singapore","arraystripslashes"), $toStrip);
  720. else
  721. return stripslashes($toStrip);
  722. }
  723. function thumbnailPath($gallery, $image, $width, $height, $forceSize, $mode = 1)
  724. {
  725. $config = sgConfig::getInstance();
  726. switch($mode) {
  727. case 0 :
  728. return $config->pathto_data_dir."cache/".$width."x".$height.($forceSize?"f":"").strtr("-$gallery-$image",":/?\\","----");
  729. case 1 :
  730. return $config->pathto_galleries.$gallery."/_thumbs/".$width."x".$height.($forceSize?"f":"").strtr("-$image",":/?\\","----");
  731. }
  732. }
  733. /**
  734. * @param string relative or absolute path to directory
  735. * @param string regular expression of files to return (optional)
  736. * @param bool true to get hidden directories too
  737. * @returns stdClass|false a data object representing the directory and its contents
  738. * @static
  739. */
  740. function getListing($wd, $mask = null, $getHidden = false)
  741. {
  742. $dir = new stdClass;
  743. $dir->path = realpath($wd)."/";
  744. $dir->files = array();
  745. $dir->dirs = array();
  746. $dp = opendir($dir->path);
  747. if(!$dp) return false;
  748. while(false !== ($entry = readdir($dp)))
  749. if(is_dir($dir->path.$entry)) {
  750. if($entry != "CVS" && $entry != ".svn" &&
  751. (($entry{0} != '.' && $entry{0} != '_') || $getHidden))
  752. $dir->dirs[] = $entry;
  753. } else {
  754. if($mask == null || preg_match("/\.($mask)$/i",$entry))
  755. $dir->files[] = $entry;
  756. }
  757. sort($dir->files);
  758. sort($dir->dirs);
  759. closedir($dp);
  760. return $dir;
  761. }
  762. /**
  763. * Recursively deletes all directories and files in the specified directory.
  764. * USE WITH EXTREME CAUTION!!
  765. * @returns boolean true on success; false otherwise
  766. * @static
  767. */
  768. function rmdir_all($wd)
  769. {
  770. if(!$dp = opendir($wd)) return false;
  771. $success = true;
  772. while(false !== ($entry = readdir($dp))) {
  773. if($entry == "." || $entry == "..") continue;
  774. if(is_dir("$wd/$entry")) $success &= Singapore::rmdir_all("$wd/$entry");
  775. else $success &= unlink("$wd/$entry");
  776. }
  777. closedir($dp);
  778. $success &= rmdir($wd);
  779. return $success;
  780. }
  781. /**
  782. * Returns an array of language codes specified in the Accept-Language HHTP
  783. * header field of the user's browser. q= components are ignored and removed.
  784. * hyphens (-) are converted to underscores (_).
  785. * @return array accepted language codes
  786. * @static
  787. */
  788. function getBrowserLanguages()
  789. {
  790. $langs = array();
  791. foreach(explode(",",$_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $bit)
  792. if($pos = strpos($bit,";"))
  793. $langs[] = strtr(substr($bit,0,$pos),"-","_");
  794. else
  795. $langs[] = strtr($bit,"-","_");
  796. return $langs;
  797. }
  798. /**
  799. * Wrapper for mkdir() implementing the safe-mode hack
  800. */
  801. function mkdir($path)
  802. {
  803. $config = sgConfig::getInstance();
  804. if($config->safe_mode_hack) {
  805. $connection = ftp_connect($config->ftp_server);
  806. // login to ftp server
  807. $result = ftp_login($connection, $config->ftp_user, $config->ftp_pass);
  808. // check if connection was made
  809. if ((!$connection) || (!$result))
  810. return false;
  811. ftp_chdir($connection, $config->ftp_base_path); // go to destination dir
  812. if(!ftp_mkdir($connection, $path)) // create directory
  813. return false;
  814. ftp_site($connection, "CHMOD ".$config->directory_mode." ".$path);
  815. ftp_close($connection); // close connection
  816. return true;
  817. } else
  818. return mkdir($path, octdec($config->directory_mode));
  819. }
  820. /**
  821. * Tests if $child is within or is the same path as $parent.
  822. *
  823. * @param string path to parent directory
  824. * @param string path to child directory or file
  825. * @param bool set false to prevent canonicalisation of paths (optional)
  826. * @return bool true if $child is contained within or is $parent
  827. */
  828. function isSubPath($parent, $child, $canonicalise = true)
  829. {
  830. $parentPath = $canonicalise ? realpath($parent) : $parent;
  831. $childPath = $canonicalise ? realpath($child) : $child;
  832. return $parentPath && $childPath && substr($childPath,0,strlen($parentPath)) == $parentPath;
  833. }
  834. function isInGroup($groups1,$groups2)
  835. {
  836. return (bool) array_intersect(explode(" ",$groups1),explode(" ",$groups2));
  837. }
  838. }
  839. ?>