PageRenderTime 50ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/FSN/mediatheque/zp-core/functions.php

https://gitlab.com/r.collas/site_central
PHP | 1651 lines | 1402 code | 51 blank | 198 comment | 148 complexity | 341fa69277a54ad1f454f8c06fda8aeb MD5 | raw file
  1. <?php
  2. /**
  3. * basic functions used by zenphoto
  4. *
  5. * @package core
  6. *
  7. */
  8. // force UTF-8 Ø
  9. global $_zp_current_context_stack, $_zp_HTML_cache;
  10. if (!function_exists("json_encode")) {
  11. // load the drop-in replacement library
  12. require_once(dirname(__FILE__) . '/lib-json.php');
  13. }
  14. require_once(dirname(__FILE__) . '/functions-basic.php');
  15. require_once(dirname(__FILE__) . '/functions-filter.php');
  16. require_once(SERVERPATH . '/' . ZENFOLDER . '/lib-kses.php');
  17. $_zp_captcha = new _zp_captcha(); // this will be overridden by the plugin if enabled.
  18. $_zp_HTML_cache = new _zp_HTML_cache(); // this will be overridden by the plugin if enabled.
  19. //setup session before checking for logon cookie
  20. require_once(dirname(__FILE__) . '/functions-i18n.php');
  21. if (GALLERY_SESSION) {
  22. zp_session_start();
  23. }
  24. define('ZENPHOTO_LOCALE', setMainDomain());
  25. define('SITE_LOCALE', getOptionFromDB('locale'));
  26. require_once(dirname(__FILE__) . '/load_objectClasses.php');
  27. $_zp_current_context_stack = array();
  28. $_zp_albumthumb_selector = array(array('field' => '', 'direction' => '', 'desc' => 'random'),
  29. array('field' => 'id', 'direction' => 'DESC', 'desc' => gettext('most recent')),
  30. array('field' => 'mtime', 'direction' => '', 'desc' => gettext('oldest')),
  31. array('field' => 'title', 'direction' => '', 'desc' => gettext('first alphabetically')),
  32. array('field' => 'hitcounter', 'direction' => 'DESC', 'desc' => gettext('most viewed'))
  33. );
  34. $_zp_missing_album = new AlbumBase(gettext('missing'), false);
  35. $_zp_missing_image = new Transientimage($_zp_missing_album, SERVERPATH . '/' . ZENFOLDER . '/images/err-imagenotfound.png');
  36. /**
  37. * parses the allowed HTML tags for use by htmLawed
  38. *
  39. * @param string &$source by name, contains the string with the tag options
  40. * @return array the allowed_tags array.
  41. * @since 1.1.3
  42. * */
  43. function parseAllowedTags(&$source) {
  44. $source = trim($source);
  45. if (substr($source, 0, 1) != "(") {
  46. return false;
  47. }
  48. $source = substr($source, 1); //strip off the open paren
  49. $a = array();
  50. while ((strlen($source) > 1) && (substr($source, 0, 1) != ")")) {
  51. $i = strpos($source, '=>');
  52. if ($i === false) {
  53. return false;
  54. }
  55. $tag = trim(substr($source, 0, $i));
  56. //strip forbidden tags from list
  57. if ($tag == 'script') {
  58. return 0;
  59. }
  60. $source = trim(substr($source, $i + 2));
  61. if (substr($source, 0, 1) != "(") {
  62. return false;
  63. }
  64. $x = parseAllowedTags($source);
  65. if ($x === false) {
  66. return false;
  67. }
  68. $a[$tag] = $x;
  69. }
  70. if (substr($source, 0, 1) != ')') {
  71. return false;
  72. }
  73. $source = trim(substr($source, 1)); //strip the close paren
  74. return $a;
  75. }
  76. /**
  77. * Search for a thumbnail for the image
  78. *
  79. * @param $localpath local path of the image
  80. * @return string
  81. */
  82. function checkObjectsThumb($localpath) {
  83. global $_zp_supported_images;
  84. $image = stripSuffix($localpath);
  85. $candidates = safe_glob($image . '.*');
  86. foreach ($candidates as $file) {
  87. $ext = substr($file, strrpos($file, '.') + 1);
  88. if (in_array(strtolower($ext), $_zp_supported_images)) {
  89. return basename($image . '.' . $ext);
  90. }
  91. }
  92. return NULL;
  93. }
  94. /**
  95. * Returns a truncated string
  96. *
  97. * @param string $string souirce string
  98. * @param int $length how long it should be
  99. * @param string $elipsis the text to tack on indicating shortening
  100. * @return string
  101. */
  102. function truncate_string($string, $length, $elipsis = '...') {
  103. if (mb_strlen($string) > $length) {
  104. $string = mb_substr($string, 0, $length);
  105. $pos = mb_strrpos(strtr($string, array('~' => ' ', '!' => ' ', '@' => ' ', '#' => ' ', '$' => ' ', '%' => ' ', '^' => ' ', '&' => ' ', '*' => ' ', '(' => ' ', ')' => ' ', '+' => ' ', '=' => ' ', '-' => ' ', '{' => ' ', '}' => ' ', '[' => ' ', ']' => ' ', '|' => ' ', ':' => ' ', ';' => ' ', '<' => ' ', '>' => ' ', '.' => ' ', '?' => ' ', '/' => ' ', '\\', '\\' => ' ', "'" => ' ', "`" => ' ', '"' => ' ')), ' ');
  106. if ($pos === FALSE) {
  107. $string .= $elipsis;
  108. } else {
  109. $string = mb_substr($string, 0, $pos) . $elipsis;
  110. }
  111. }
  112. return $string;
  113. }
  114. /**
  115. *
  116. * fixes unbalanced HTML tags. Used by shortenContent when PHP tidy is not present
  117. * @param string $html
  118. * @return string
  119. */
  120. function cleanHTML($html) {
  121. preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);
  122. $openedtags = $result[1];
  123. preg_match_all('#</([a-z]+)>#iU', $html, $result);
  124. $closedtags = $result[1];
  125. $len_opened = count($openedtags);
  126. if (count($closedtags) == $len_opened) {
  127. return $html;
  128. }
  129. $openedtags = array_reverse($openedtags);
  130. for ($i = 0; $i < $len_opened; $i++) {
  131. if (!in_array($openedtags[$i], $closedtags)) {
  132. $html .= '</' . $openedtags[$i] . '>';
  133. } else {
  134. unset($closedtags[array_search($openedtags[$i], $closedtags)]);
  135. }
  136. }
  137. return $html;
  138. }
  139. /**
  140. * Returns truncated html formatted content
  141. *
  142. * @param string $articlecontent the source string
  143. * @param int $shorten new size
  144. * @param string $shortenindicator
  145. * @param bool $forceindicator set to true to include the indicator no matter what
  146. * @return string
  147. */
  148. function shortenContent($articlecontent, $shorten, $shortenindicator, $forceindicator = false) {
  149. global $_user_tags;
  150. if ($shorten && ($forceindicator || (mb_strlen($articlecontent) > $shorten))) {
  151. $allowed_tags = getAllowedTags('allowed_tags');
  152. //remove script to be replaced later
  153. $articlecontent = preg_replace('~<script.*?/script>~is', '', $articlecontent);
  154. //remove HTML comments
  155. $articlecontent = preg_replace('~<!--.*?-->~is', '', $articlecontent);
  156. $short = mb_substr($articlecontent, 0, $shorten);
  157. $short2 = kses($short . '</p>', $allowed_tags);
  158. if (($l2 = mb_strlen($short2)) < $shorten) {
  159. $c = 0;
  160. $l1 = $shorten;
  161. $delta = $shorten - $l2;
  162. while ($l2 < $shorten && $c++ < 5) {
  163. $open = mb_strrpos($short, '<');
  164. if ($open > mb_strrpos($short, '>')) {
  165. $l1 = mb_strpos($articlecontent, '>', $l1 + 1) + $delta;
  166. } else {
  167. $l1 = $l1 + $delta;
  168. }
  169. $short = mb_substr($articlecontent, 0, $l1);
  170. preg_match_all('/(<p>)/', $short, $open);
  171. preg_match_all('/(<\/p>)/', $short, $close);
  172. if (count($open) > count($close))
  173. $short .= '</p>';
  174. $short2 = kses($short, $allowed_tags);
  175. $l2 = mb_strlen($short2);
  176. }
  177. $shorten = $l1;
  178. }
  179. $short = truncate_string($articlecontent, $shorten, '');
  180. if ($short != $articlecontent) { // we actually did remove some stuff
  181. // drop open tag strings
  182. $open = mb_strrpos($short, '<');
  183. if ($open > mb_strrpos($short, '>')) {
  184. $short = mb_substr($short, 0, $open);
  185. }
  186. if (class_exists('tidy')) {
  187. $tidy = new tidy();
  188. $tidy->parseString($short . $shortenindicator, array('show-body-only' => true), 'utf8');
  189. $tidy->cleanRepair();
  190. $short = trim($tidy);
  191. } else {
  192. $short = trim(cleanHTML($short . $shortenindicator));
  193. }
  194. }
  195. $articlecontent = $short;
  196. }
  197. if (isset($matches)) {
  198. //replace the script text
  199. foreach ($matches[0] as $script) {
  200. $articlecontent = $script . $articlecontent;
  201. }
  202. }
  203. return $articlecontent;
  204. }
  205. /**
  206. * Returns the oldest ancestor of an alubm;
  207. *
  208. * @param string $album an album object
  209. * @return object
  210. */
  211. function getUrAlbum($album) {
  212. if (!is_object($album))
  213. return NULL;
  214. while (true) {
  215. $parent = $album->getParent();
  216. if (is_null($parent)) {
  217. return $album;
  218. }
  219. $album = $parent;
  220. }
  221. }
  222. /**
  223. * Returns a sort field part for querying
  224. * Note: $sorttype may be a comma separated list of field names. If so,
  225. * these are peckmarked and returned otherwise unchanged.
  226. *
  227. * @param string $sorttype the 'Display" name of the sort
  228. * @param string $default the default if $sorttype is empty
  229. * @param string $table the database table being used.
  230. * @return string
  231. */
  232. function lookupSortKey($sorttype, $default, $table) {
  233. global $_zp_fieldLists;
  234. switch (strtolower($sorttype)) {
  235. case 'random':
  236. return 'RAND()';
  237. case "manual":
  238. return '`sort_order`';
  239. case "filename":
  240. switch ($table) {
  241. case 'images':
  242. return '`filename`';
  243. case 'albums':
  244. return '`folder`';
  245. }
  246. default:
  247. if (empty($sorttype)) {
  248. return '`' . $default . '`';
  249. }
  250. if (substr($sorttype, 0) == '(') {
  251. return $sorttype;
  252. }
  253. if (is_array($_zp_fieldLists) && isset($_zp_fieldLists[$table])) {
  254. $dbfields = $_zp_fieldLists[$table];
  255. } else {
  256. $result = db_list_fields($table);
  257. $dbfields = array();
  258. if ($result) {
  259. foreach ($result as $row) {
  260. $dbfields[strtolower($row['Field'])] = $row['Field'];
  261. }
  262. }
  263. $_zp_fieldLists[$table] = $dbfields;
  264. }
  265. $sorttype = strtolower($sorttype);
  266. $list = explode(',', $sorttype);
  267. foreach ($list as $key => $field) {
  268. if (array_key_exists($field, $dbfields)) {
  269. $list[$key] = '`' . trim($dbfields[$field]) . '`';
  270. }
  271. }
  272. return implode(',', $list);
  273. }
  274. }
  275. /**
  276. * Returns a formated date for output
  277. *
  278. * @param string $format the "strftime" format string
  279. * @param date $dt the date to be output
  280. * @return string
  281. */
  282. function zpFormattedDate($format, $dt) {
  283. global $_zp_UTF8;
  284. $fdate = strftime($format, $dt);
  285. $charset = 'ISO-8859-1';
  286. $outputset = LOCAL_CHARSET;
  287. if (function_exists('mb_internal_encoding')) {
  288. if (($charset = mb_internal_encoding()) == $outputset) {
  289. return $fdate;
  290. }
  291. }
  292. return $_zp_UTF8->convert($fdate, $charset, $outputset);
  293. }
  294. /**
  295. * Simple SQL timestamp formatting function.
  296. *
  297. * @param string $format formatting template
  298. * @param int $mytimestamp timestamp
  299. * @return string
  300. */
  301. function myts_date($format, $mytimestamp) {
  302. $timezoneadjust = getOption('time_offset');
  303. $month = substr($mytimestamp, 4, 2);
  304. $day = substr($mytimestamp, 6, 2);
  305. $year = substr($mytimestamp, 0, 4);
  306. $hour = substr($mytimestamp, 8, 2);
  307. $min = substr($mytimestamp, 10, 2);
  308. $sec = substr($mytimestamp, 12, 2);
  309. $epoch = mktime($hour + $timezoneadjust, $min, $sec, $month, $day, $year);
  310. $date = zpFormattedDate($format, $epoch);
  311. return $date;
  312. }
  313. /**
  314. * Determines if the input is an e-mail address. Adapted from WordPress.
  315. * Name changed to avoid conflicts in WP integrations.
  316. *
  317. * @param string $input_email email address?
  318. * @return bool
  319. */
  320. function is_valid_email_zp($input_email) {
  321. $chars = "/^([a-z0-9+_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,6}\$/i";
  322. if (strstr($input_email, '@') && strstr($input_email, '.')) {
  323. if (preg_match($chars, $input_email)) {
  324. return true;
  325. }
  326. }
  327. return false;
  328. }
  329. /**
  330. * Send an mail to the mailing list. We also attempt to intercept any form injection
  331. * attacks by slime ball spammers. Returns error message if send failure.
  332. *
  333. * @param string $subject The subject of the email.
  334. * @param string $message The message contents of the email.
  335. * @param array $email_list a list of email addresses to send to
  336. * @param array $cc_addresses a list of addresses to send copies to.
  337. * @param array $bcc_addresses a list of addresses to send blind copies to.
  338. * @param string $replyTo reply-to address
  339. *
  340. * @return string
  341. *
  342. * @author Todd Papaioannou (lucky@luckyspin.org)
  343. * @since 1.0.0
  344. */
  345. function zp_mail($subject, $message, $email_list = NULL, $cc_addresses = NULL, $bcc_addresses = NULL, $replyTo = NULL) {
  346. global $_zp_authority, $_zp_gallery, $_zp_UTF8;
  347. $result = '';
  348. if ($replyTo) {
  349. $t = $replyTo;
  350. if (!is_valid_email_zp($m = array_shift($t))) {
  351. if (empty($result)) {
  352. $result = gettext('Mail send failed.');
  353. }
  354. $result .= sprintf(gettext('Invalid “reply-to” mail address %s.'), $m);
  355. }
  356. }
  357. if (is_null($email_list)) {
  358. $email_list = $_zp_authority->getAdminEmail();
  359. } else {
  360. foreach ($email_list as $key => $email) {
  361. if (!is_valid_email_zp($email)) {
  362. unset($email_list[$key]);
  363. if (empty($result)) {
  364. $result = gettext('Mail send failed.');
  365. }
  366. $result .= ' ' . sprintf(gettext('Invalid “to” mail address %s.'), $email);
  367. }
  368. }
  369. }
  370. if (is_null($cc_addresses)) {
  371. $cc_addresses = array();
  372. } else {
  373. if (empty($email_list) && !empty($cc_addresses)) {
  374. if (empty($result)) {
  375. $result = gettext('Mail send failed.');
  376. }
  377. $result .= ' ' . gettext('“cc” list provided without “to” address list.');
  378. return $result;
  379. }
  380. foreach ($cc_addresses as $key => $email) {
  381. if (!is_valid_email_zp($email)) {
  382. unset($cc_addresses[$key]);
  383. if (empty($result)) {
  384. $result = gettext('Mail send failed.');
  385. }
  386. $result = ' ' . sprintf(gettext('Invalid “cc” mail address %s.'), $email);
  387. }
  388. }
  389. }
  390. if (is_null($bcc_addresses)) {
  391. $bcc_addresses = array();
  392. } else {
  393. foreach ($bcc_addresses as $key => $email) {
  394. if (!is_valid_email_zp($email)) {
  395. unset($bcc_addresses[$key]);
  396. if (empty($result)) {
  397. $result = gettext('Mail send failed.');
  398. }
  399. $result = ' ' . sprintf(gettext('Invalid “bcc” mail address %s.'), $email);
  400. }
  401. }
  402. }
  403. if (count($email_list) + count($bcc_addresses) > 0) {
  404. if (zp_has_filter('sendmail')) {
  405. $from_mail = getOption('site_email');
  406. $from_name = get_language_string(getOption('site_email_name'));
  407. // Convert to UTF-8
  408. if (LOCAL_CHARSET != 'UTF-8') {
  409. $subject = $_zp_UTF8->convert($subject, LOCAL_CHARSET);
  410. $message = $_zp_UTF8->convert($message, LOCAL_CHARSET);
  411. }
  412. // we do not support rich text
  413. $message = preg_replace('~<p[^>]*>~', "\n", $message); // Replace the start <p> or <p attr="">
  414. $message = preg_replace('~</p>~', "\n", $message); // Replace the end
  415. $message = preg_replace('~<br[^>]*>~', "\n", $message); // Replace <br> or <br ...>
  416. $message = preg_replace('~<ol[^>]*>~', "", $message); // Replace the start <ol> or <ol attr="">
  417. $message = preg_replace('~</ol>~', "", $message); // Replace the end
  418. $message = preg_replace('~<ul[^>]*>~', "", $message); // Replace the start <ul> or <ul attr="">
  419. $message = preg_replace('~</ul>~', "", $message); // Replace the end
  420. $message = preg_replace('~<li[^>]*>~', ".\t", $message); // Replace the start <li> or <li attr="">
  421. $message = preg_replace('~</li>~', "", $message); // Replace the end
  422. $message = getBare($message);
  423. $message = preg_replace('~\n\n\n+~', "\n\n", $message);
  424. // Send the mail
  425. if (count($email_list) > 0) {
  426. $result = zp_apply_filter('sendmail', '', $email_list, $subject, $message, $from_mail, $from_name, $cc_addresses, $replyTo); // will be true if all mailers succeeded
  427. }
  428. if (count($bcc_addresses) > 0) {
  429. foreach ($bcc_addresses as $bcc) {
  430. $result = zp_apply_filter('sendmail', '', array($bcc), $subject, $message, $from_mail, $from_name, array(), $replyTo); // will be true if all mailers succeeded
  431. }
  432. }
  433. } else {
  434. $result = gettext('Mail send failed. There is no mail handler configured.');
  435. }
  436. } else {
  437. if (empty($result)) {
  438. $result = gettext('Mail send failed.');
  439. }
  440. $result .= ' ' . gettext('No “to” address list provided.');
  441. }
  442. return $result;
  443. }
  444. /**
  445. * Sorts the results of a DB search by the current locale string for $field
  446. *
  447. * @param array $dbresult the result of the DB query
  448. * @param string $field the field name to sort on
  449. * @param bool $descending the direction of the sort
  450. * @return array the sorted result
  451. */
  452. function sortByMultilingual($dbresult, $field, $descending) {
  453. $temp = array();
  454. foreach ($dbresult as $key => $row) {
  455. $temp[$key] = get_language_string($row[$field]);
  456. }
  457. natcasesort($temp);
  458. if ($descending) {
  459. $temp = array_reverse($temp, true);
  460. }
  461. $result = array();
  462. foreach ($temp as $key => $v) {
  463. $result[] = $dbresult[$key];
  464. }
  465. return $result;
  466. }
  467. /**
  468. * Checks to see access is allowed to an album
  469. * Returns true if access is allowed.
  470. * There is no password dialog--you must have already had authorization via a cookie.
  471. *
  472. * @param string $album album object or name of the album
  473. * @param string &$hint becomes populated with the password hint.
  474. * @return bool
  475. */
  476. function checkAlbumPassword($album, &$hint = NULL) {
  477. global $_zp_pre_authorization, $_zp_gallery;
  478. if (is_object($album)) {
  479. $albumname = $album->name;
  480. } else {
  481. $album = newAlbum($albumname = $album, true, true);
  482. }
  483. if (isset($_zp_pre_authorization[$albumname])) {
  484. return $_zp_pre_authorization[$albumname];
  485. }
  486. $hash = $album->getPassword();
  487. if (empty($hash)) {
  488. $album = $album->getParent();
  489. while (!is_null($album)) {
  490. $hash = $album->getPassword();
  491. $authType = "zp_album_auth_" . $album->getID();
  492. $saved_auth = zp_getCookie($authType);
  493. if (!empty($hash)) {
  494. if ($saved_auth == $hash) {
  495. $_zp_pre_authorization[$albumname] = $authType;
  496. return $authType;
  497. } else {
  498. $hint = $album->getPasswordHint();
  499. return false;
  500. }
  501. }
  502. $album = $album->getParent();
  503. }
  504. // revert all tlhe way to the gallery
  505. $hash = $_zp_gallery->getPassword();
  506. $authType = 'zp_gallery_auth';
  507. $saved_auth = zp_getCookie($authType);
  508. if (empty($hash)) {
  509. $authType = 'zp_public_access';
  510. } else {
  511. if ($saved_auth != $hash) {
  512. $hint = $_zp_gallery->getPasswordHint();
  513. return false;
  514. }
  515. }
  516. } else {
  517. $authType = "zp_album_auth_" . $album->getID();
  518. $saved_auth = zp_getCookie($authType);
  519. if ($saved_auth != $hash) {
  520. $hint = $album->getPasswordHint();
  521. return false;
  522. }
  523. }
  524. $_zp_pre_authorization[$albumname] = $authType;
  525. return $authType;
  526. }
  527. /**
  528. * Returns a consolidated list of plugins
  529. * The array structure is key=plugin name, value=plugin path
  530. *
  531. * @param string $pattern File system wildcard matching pattern to limit the search
  532. * @param string $folder subfolder within the plugin folders to search
  533. * @param bool $stripsuffix set to true to remove the suffix from the key name in the array
  534. * @return array
  535. */
  536. function getPluginFiles($pattern, $folder = '', $stripsuffix = true) {
  537. if (!empty($folder) && substr($folder, -1) != '/')
  538. $folder .= '/';
  539. $list = array();
  540. $curdir = getcwd();
  541. $basepath = SERVERPATH . "/" . USER_PLUGIN_FOLDER . '/' . $folder;
  542. if (is_dir($basepath)) {
  543. chdir($basepath);
  544. $filelist = safe_glob($pattern);
  545. foreach ($filelist as $file) {
  546. $key = filesystemToInternal($file);
  547. if ($stripsuffix) {
  548. $key = stripSuffix($key);
  549. }
  550. $list[$key] = $basepath . $file;
  551. }
  552. }
  553. $basepath = SERVERPATH . "/" . ZENFOLDER . '/' . PLUGIN_FOLDER . '/' . $folder;
  554. if (file_exists($basepath)) {
  555. chdir($basepath);
  556. $filelist = safe_glob($pattern);
  557. foreach ($filelist as $file) {
  558. $key = filesystemToInternal($file);
  559. if ($stripsuffix) {
  560. $key = stripSuffix($key);
  561. }
  562. $list[$key] = $basepath . $file;
  563. }
  564. }
  565. chdir($curdir);
  566. return $list;
  567. }
  568. /**
  569. * Returns the fully qualified file name of the plugin file.
  570. *
  571. * Note: order of selection is:
  572. * 1-theme folder file (if $inTheme is set)
  573. * 2-user plugin folder file
  574. * 3-zp-extensions file
  575. * first file found is used
  576. *
  577. * @param string $plugin is the name of the plugin file, typically something.php
  578. * @param bool $inTheme tells where to find the plugin.
  579. * true means look in the current theme
  580. * false means look in the zp-core/plugins folder.
  581. * @param bool $webpath return a WEBPATH rather than a SERVERPATH
  582. *
  583. * @return string
  584. */
  585. function getPlugin($plugin, $inTheme = false, $webpath = false) {
  586. global $_zp_gallery;
  587. $pluginFile = NULL;
  588. if ($inTheme === true) {
  589. $inTheme = $_zp_gallery->getCurrentTheme();
  590. }
  591. if ($inTheme) {
  592. $pluginFile = '/' . THEMEFOLDER . '/' . internalToFilesystem($inTheme . '/' . $plugin);
  593. if (!file_exists(SERVERPATH . $pluginFile)) {
  594. $pluginFile = false;
  595. }
  596. }
  597. if (!$pluginFile) {
  598. $pluginFile = '/' . USER_PLUGIN_FOLDER . '/' . internalToFilesystem($plugin);
  599. if (!file_exists(SERVERPATH . $pluginFile)) {
  600. $pluginFile = '/' . ZENFOLDER . '/' . PLUGIN_FOLDER . '/' . internalToFilesystem($plugin);
  601. if (!file_exists(SERVERPATH . $pluginFile)) {
  602. $pluginFile = false;
  603. }
  604. }
  605. }
  606. if ($pluginFile) {
  607. if ($webpath) {
  608. if (is_string($webpath)) {
  609. return $webpath . filesystemToInternal($pluginFile);
  610. } else {
  611. return WEBPATH . filesystemToInternal($pluginFile);
  612. }
  613. } else {
  614. return SERVERPATH . $pluginFile;
  615. }
  616. }
  617. return false;
  618. }
  619. /**
  620. * Returns an array of the currently enabled plugins
  621. *
  622. * @return array
  623. */
  624. function getEnabledPlugins() {
  625. global $_EnabledPlugins;
  626. if (is_array($_EnabledPlugins)) {
  627. return $_EnabledPlugins;
  628. }
  629. $_EnabledPlugins = array();
  630. $sortlist = getPluginFiles('*.php');
  631. foreach ($sortlist as $extension => $path) {
  632. $opt = 'zp_plugin_' . $extension;
  633. if ($option = getOption($opt)) {
  634. $_EnabledPlugins[$extension] = array('priority' => $option, 'path' => $path);
  635. }
  636. }
  637. $_EnabledPlugins = sortMultiArray($_EnabledPlugins, 'priority', true);
  638. return $_EnabledPlugins;
  639. }
  640. /**
  641. * Returns if a plugin is enabled
  642. * @param string $extension
  643. * @return bool
  644. */
  645. function extensionEnabled($extension) {
  646. return getOption('zp_plugin_' . $extension);
  647. }
  648. /**
  649. * Enables a plugin
  650. * @param string $extension
  651. * @param int $priority
  652. * @param bool $persistent
  653. */
  654. function enableExtension($extension, $priority, $persistent = true) {
  655. setOption('zp_plugin_' . $extension, $priority, $persistent);
  656. }
  657. /**
  658. * Gets an array of comments for the current admin
  659. *
  660. * @param int $number how many comments desired
  661. * @return array
  662. */
  663. function fetchComments($number) {
  664. if ($number) {
  665. $limit = " LIMIT $number";
  666. } else {
  667. $limit = '';
  668. }
  669. $comments = array();
  670. if (zp_loggedin(ADMIN_RIGHTS | COMMENT_RIGHTS)) {
  671. if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS)) {
  672. $sql = "SELECT *, (date + 0) AS date FROM " . prefix('comments') . " ORDER BY id DESC$limit";
  673. $comments = query_full_array($sql);
  674. } else {
  675. $albumlist = getManagedAlbumList();
  676. $albumIDs = array();
  677. foreach ($albumlist as $albumname) {
  678. $subalbums = getAllSubAlbumIDs($albumname);
  679. foreach ($subalbums as $ID) {
  680. $albumIDs[] = $ID['id'];
  681. }
  682. }
  683. if (count($albumIDs) > 0) {
  684. $sql = "SELECT *, (`date` + 0) AS date FROM " . prefix('comments') . " WHERE ";
  685. $sql .= " (`type`='albums' AND (";
  686. $i = 0;
  687. foreach ($albumIDs as $ID) {
  688. if ($i > 0) {
  689. $sql .= " OR ";
  690. }
  691. $sql .= "(" . prefix('comments') . ".ownerid=$ID)";
  692. $i++;
  693. }
  694. $sql .= ")) ";
  695. $sql .= " ORDER BY id DESC$limit";
  696. $albumcomments = query($sql);
  697. if ($albumcomments) {
  698. while ($comment = db_fetch_assoc($albumcomments)) {
  699. $comments[$comment['id']] = $comment;
  700. }
  701. db_free_result($albumcomments);
  702. }
  703. $sql = "SELECT *, " . prefix('comments') . ".id as id, " .
  704. prefix('comments') . ".name as name, (" . prefix('comments') . ".date + 0) AS date, " .
  705. prefix('images') . ".`albumid` as albumid," .
  706. prefix('images') . ".`id` as imageid" .
  707. " FROM " . prefix('comments') . "," . prefix('images') . " WHERE ";
  708. $sql .= "(`type` IN (" . zp_image_types("'") . ") AND (";
  709. $i = 0;
  710. foreach ($albumIDs as $ID) {
  711. if ($i > 0) {
  712. $sql .= " OR ";
  713. }
  714. $sql .= "(" . prefix('comments') . ".ownerid=" . prefix('images') . ".id AND " . prefix('images') . ".albumid=$ID)";
  715. $i++;
  716. }
  717. $sql .= "))";
  718. $sql .= " ORDER BY " . prefix('images') . ".`id` DESC$limit";
  719. $imagecomments = query($sql);
  720. if ($imagecomments) {
  721. while ($comment = db_fetch_assoc($imagecomments)) {
  722. $comments[$comment['id']] = $comment;
  723. }
  724. db_free_result($imagecomments);
  725. }
  726. krsort($comments);
  727. if ($number) {
  728. if ($number < count($comments)) {
  729. $comments = array_slice($comments, 0, $number);
  730. }
  731. }
  732. }
  733. }
  734. }
  735. return $comments;
  736. }
  737. /**
  738. * Populates and returns the $_zp_admin_album_list array
  739. * @return array
  740. */
  741. function getManagedAlbumList() {
  742. global $_zp_admin_album_list, $_zp_current_admin_obj;
  743. $_zp_admin_album_list = array();
  744. if (zp_loggedin(MANAGE_ALL_ALBUM_RIGHTS)) {
  745. $sql = "SELECT `folder` FROM " . prefix('albums') . ' WHERE `parentid` IS NULL';
  746. $albums = query($sql);
  747. if ($albums) {
  748. while ($album = db_fetch_assoc($albums)) {
  749. $_zp_admin_album_list[$album['folder']] = 32767;
  750. }
  751. db_free_result($albums);
  752. }
  753. } else {
  754. if ($_zp_current_admin_obj) {
  755. $_zp_admin_album_list = array();
  756. $objects = $_zp_current_admin_obj->getObjects();
  757. foreach ($objects as $object) {
  758. if ($object['type'] == 'album') {
  759. $_zp_admin_album_list[$object['data']] = $object['edit'];
  760. }
  761. }
  762. }
  763. }
  764. return array_keys($_zp_admin_album_list);
  765. }
  766. /**
  767. * Returns a list of album names managed by $id
  768. *
  769. * @param string $type which kind of object
  770. * @param int $id admin ID
  771. * @param bool $rights set true for album sub-rights
  772. * @return array
  773. */
  774. function populateManagedObjectsList($type, $id, $rights = false) {
  775. if ($id <= 0) {
  776. return array();
  777. }
  778. $cv = array();
  779. if (empty($type) || substr($type, 0, 5) == 'album') {
  780. $sql = "SELECT " . prefix('albums') . ".`folder`," . prefix('albums') . ".`title`," . prefix('admin_to_object') . ".`edit` FROM " . prefix('albums') . ", " .
  781. prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
  782. " AND " . prefix('albums') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type LIKE 'album%'";
  783. $currentvalues = query($sql, false);
  784. if ($currentvalues) {
  785. while ($albumitem = db_fetch_assoc($currentvalues)) {
  786. $folder = $albumitem['folder'];
  787. $name = get_language_string($albumitem['title']);
  788. if ($type && !$rights) {
  789. $cv[$name] = $folder;
  790. } else {
  791. $cv[] = array('data' => $folder, 'name' => $name, 'type' => 'album', 'edit' => $albumitem['edit'] + 0);
  792. }
  793. }
  794. db_free_result($currentvalues);
  795. }
  796. }
  797. if (empty($type) || $type == 'pages') {
  798. $sql = 'SELECT ' . prefix('pages') . '.`title`,' . prefix('pages') . '.`titlelink` FROM ' . prefix('pages') . ', ' .
  799. prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
  800. " AND " . prefix('pages') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type='pages'";
  801. $currentvalues = query($sql, false);
  802. if ($currentvalues) {
  803. while ($item = db_fetch_assoc($currentvalues)) {
  804. if ($type) {
  805. $cv[get_language_string($item['title'])] = $item['titlelink'];
  806. } else {
  807. $cv[] = array('data' => $item['titlelink'], 'name' => $item['title'], 'type' => 'pages');
  808. }
  809. }
  810. db_free_result($currentvalues);
  811. }
  812. }
  813. if (empty($type) || $type == 'news') {
  814. $sql = 'SELECT ' . prefix('news_categories') . '.`titlelink`,' . prefix('news_categories') . '.`title` FROM ' . prefix('news_categories') . ', ' .
  815. prefix('admin_to_object') . " WHERE " . prefix('admin_to_object') . ".adminid=" . $id .
  816. " AND " . prefix('news_categories') . ".id=" . prefix('admin_to_object') . ".objectid AND " . prefix('admin_to_object') . ".type='news'";
  817. $currentvalues = query($sql, false);
  818. if ($currentvalues) {
  819. while ($item = db_fetch_assoc($currentvalues)) {
  820. if ($type) {
  821. $cv[get_language_string($item['title'])] = $item['titlelink'];
  822. } else {
  823. $cv[] = array('data' => $item['titlelink'], 'name' => $item['title'], 'type' => 'news');
  824. }
  825. }
  826. db_free_result($currentvalues);
  827. }
  828. }
  829. return $cv;
  830. }
  831. /**
  832. * Returns an array of album ids whose parent is the folder
  833. * @param string $albumfolder folder name if you want a album different >>from the current album
  834. * @return array
  835. */
  836. function getAllSubAlbumIDs($albumfolder = '') {
  837. global $_zp_current_album;
  838. if (empty($albumfolder)) {
  839. if (isset($_zp_current_album)) {
  840. $albumfolder = $_zp_current_album->getFileName();
  841. } else {
  842. return null;
  843. }
  844. }
  845. $query = "SELECT `id`,`folder`, `show` FROM " . prefix('albums') . " WHERE `folder` LIKE " . db_quote(db_LIKE_escape($albumfolder) . '%');
  846. $subIDs = query_full_array($query);
  847. return $subIDs;
  848. }
  849. /**
  850. * recovers search parameters from stored cookie, clears the cookie
  851. *
  852. * @param string $what the page type
  853. * @param string $album Name of the album
  854. * @param string $image Name of the image
  855. */
  856. function handleSearchParms($what, $album = NULL, $image = NULL) {
  857. global $_zp_current_search, $zp_request, $_zp_last_album, $_zp_current_album,
  858. $_zp_current_zenpage_news, $_zp_current_zenpage_page, $_zp_gallery, $_zp_loggedin;
  859. $_zp_last_album = zp_getCookie('zenphoto_last_album');
  860. if (is_object($zp_request) && get_class($zp_request) == 'SearchEngine') { // we are are on a search
  861. return $zp_request->getAlbumList();
  862. }
  863. $params = zp_getCookie('zenphoto_search_params');
  864. if (!empty($params)) {
  865. $context = get_context();
  866. $_zp_current_search = new SearchEngine();
  867. $_zp_current_search->setSearchParams($params);
  868. // check to see if we are still "in the search context"
  869. if (!is_null($image)) {
  870. $dynamic_album = $_zp_current_search->getDynamicAlbum();
  871. if ($_zp_current_search->getImageIndex($album->name, $image->filename) !== false) {
  872. if ($dynamic_album) {
  873. $_zp_current_album = $dynamic_album;
  874. }
  875. $context = $context | ZP_SEARCH_LINKED | ZP_IMAGE_LINKED;
  876. }
  877. }
  878. if (!is_null($album)) {
  879. $albumname = $album->name;
  880. zp_setCookie('zenphoto_last_album', $albumname);
  881. if (hasDynamicAlbumSuffix($albumname) && !is_dir(ALBUM_FOLDER_SERVERPATH . $albumname)) {
  882. $albumname = stripSuffix($albumname); // strip off the suffix as it will not be reflected in the search path
  883. }
  884. // see if the album is within the search context. NB for these purposes we need to look at all albums!
  885. $save_logon = $_zp_loggedin;
  886. $_zp_loggedin = $_zp_loggedin | VIEW_ALL_RIGHTS;
  887. $search_album_list = $_zp_current_search->getAlbums(0);
  888. $_zp_loggedin = $save_logon;
  889. foreach ($search_album_list as $searchalbum) {
  890. if (strpos($albumname, $searchalbum) !== false) {
  891. $context = $context | ZP_SEARCH_LINKED | ZP_ALBUM_LINKED;
  892. break;
  893. }
  894. }
  895. } else {
  896. zp_clearCookie('zenphoto_last_album');
  897. }
  898. if (!is_null($_zp_current_zenpage_page)) {
  899. $pages = $_zp_current_search->getPages();
  900. if (!empty($pages)) {
  901. $tltlelink = $_zp_current_zenpage_page->getTitlelink();
  902. foreach ($pages as $apage) {
  903. if ($apage == $tltlelink) {
  904. $context = $context | ZP_SEARCH_LINKED;
  905. break;
  906. }
  907. }
  908. }
  909. }
  910. if (!is_null($_zp_current_zenpage_news)) {
  911. $news = $_zp_current_search->getArticles(0, NULL, true);
  912. if (!empty($news)) {
  913. $tltlelink = $_zp_current_zenpage_news->getTitlelink();
  914. foreach ($news as $anews) {
  915. if ($anews['titlelink'] == $tltlelink) {
  916. $context = $context | ZP_SEARCH_LINKED;
  917. break;
  918. }
  919. }
  920. }
  921. }
  922. if (($context & ZP_SEARCH_LINKED)) {
  923. set_context($context);
  924. } else { // not an object in the current search path
  925. $_zp_current_search = null;
  926. rem_context(ZP_SEARCH);
  927. if (!isset($_REQUEST['preserve_serch_params'])) {
  928. zp_clearCookie("zenphoto_search_params");
  929. }
  930. }
  931. }
  932. }
  933. /**
  934. *
  935. * checks if the item has expired
  936. * @param array $row database row of the object
  937. */
  938. function checkPublishDates($row) {
  939. if (@$row['show']) {
  940. if (isset($row['expiredate']) && $row['expiredate'] && $row['expiredate'] != '0000-00-00 00:00:00') {
  941. if ($row['expiredate'] <= date('Y-m-d H:i:s')) {
  942. return 1;
  943. }
  944. }
  945. if (isset($row['publishdate']) && $row['publishdate'] && $row['publishdate'] != '0000-00-00 00:00:00') {
  946. if ($row['publishdate'] >= date('Y-m-d H:i:s')) {
  947. return 2;
  948. }
  949. }
  950. return null;
  951. }
  952. }
  953. /**
  954. * Returns the number of album thumbs that go on a gallery page
  955. *
  956. * @return int
  957. */
  958. function galleryAlbumsPerPage() {
  959. return max(1, getOption('albums_per_page'));
  960. }
  961. /**
  962. * Returns the theme folder
  963. * If there is an album theme, loads the theme options.
  964. *
  965. * @param object $album album object if override desired
  966. *
  967. * @return string
  968. */
  969. function setupTheme($album = NULL) {
  970. global $_zp_gallery, $_zp_current_album, $_zp_current_search, $_zp_themeroot;
  971. $albumtheme = '';
  972. if (is_null($album)) {
  973. if (in_context(ZP_SEARCH_LINKED)) {
  974. if (!$album = $_zp_current_search->getDynamicAlbum()) {
  975. $album = $_zp_current_album;
  976. }
  977. } else {
  978. $album = $_zp_current_album;
  979. }
  980. }
  981. $theme = $_zp_gallery->getCurrentTheme();
  982. $id = 0;
  983. if (!is_null($album)) {
  984. $parent = getUrAlbum($album);
  985. $albumtheme = $parent->getAlbumTheme();
  986. if (!empty($albumtheme)) {
  987. $theme = $albumtheme;
  988. $id = $parent->getID();
  989. }
  990. }
  991. $theme = zp_apply_filter('setupTheme', $theme);
  992. $_zp_gallery->setCurrentTheme($theme);
  993. $themeindex = getPlugin('index.php', $theme);
  994. if (empty($theme) || empty($themeindex)) {
  995. header('Last-Modified: ' . ZP_LAST_MODIFIED);
  996. header('Content-Type: text/html; charset=' . LOCAL_CHARSET);
  997. ?>
  998. <!DOCTYPE html>
  999. <html xmlns="http://www.w3.org/1999/xhtml">
  1000. <head>
  1001. </head>
  1002. <body>
  1003. <strong><?php printf(gettext('Zenphoto found no theme scripts. Please check the <em>%s</em> folder of your installation.'), THEMEFOLDER); ?></strong>
  1004. </body>
  1005. </html>
  1006. <?php
  1007. exitZP();
  1008. } else {
  1009. loadLocalOptions($id, $theme);
  1010. $_zp_themeroot = WEBPATH . "/" . THEMEFOLDER . "/$theme";
  1011. }
  1012. return $theme;
  1013. }
  1014. /**
  1015. * Returns an array of unique tag names
  1016. *
  1017. * @param bool $checkaccess Set to true if you wish to exclude tags that are assigned to items (or are not assigned at all) the visitor is not allowed to see
  1018. * Beware that this may cause overhead on large sites. Usage of the static_html_cache plugin is strongely recommended.
  1019. * @return array
  1020. */
  1021. function getAllTagsUnique($checkaccess = false) {
  1022. global $_zp_unique_tags, $_zp_unique_tags_excluded;
  1023. if(zp_loggedin(VIEW_ALL_RIGHTS)) {
  1024. $checkaccess = false;
  1025. }
  1026. //need to cache all and filtered tags indiviually
  1027. if ($checkaccess) {
  1028. if (!is_null($_zp_unique_tags_excluded)) {
  1029. return $_zp_unique_tags_excluded; // cache them.
  1030. }
  1031. } else {
  1032. if (!is_null($_zp_unique_tags)) {
  1033. return $_zp_unique_tags; // cache them.
  1034. }
  1035. }
  1036. $all_unique_tags = array();
  1037. $sql = "SELECT DISTINCT `name`, `id` FROM " . prefix('tags') . ' ORDER BY `name`';
  1038. $unique_tags = query($sql);
  1039. if ($unique_tags) {
  1040. while ($tagrow = db_fetch_assoc($unique_tags)) {
  1041. if ($checkaccess) {
  1042. if (getTagCountByAccess($tagrow) != 0) {
  1043. $all_unique_tags[] = $tagrow['name'];
  1044. }
  1045. } else {
  1046. $all_unique_tags[] = $tagrow['name'];
  1047. }
  1048. }
  1049. db_free_result($unique_tags);
  1050. }
  1051. if ($checkaccess) {
  1052. $_zp_unique_tags_excluded = $all_unique_tags;
  1053. return $_zp_unique_tags_excluded;
  1054. } else {
  1055. $_zp_unique_tags = $all_unique_tags;
  1056. return $_zp_unique_tags;
  1057. }
  1058. }
  1059. /**
  1060. * Returns an array indexed by 'tag' with the element value the count of the tag
  1061. *
  1062. * @param bool $exclude_unassigned Set to true if you wish to exclude tags that are not assigne to any item
  1063. * @param bool $checkaccess Set to true if you wish to exclude tags that are assigned to items (or are not assigned at all) the visitor is not allowed to see
  1064. * If set to true it overrides the $exclude_unassigned parameter.
  1065. * Beware that this may cause overhead on large sites. Usage of the static_html_cache plugin is strongely recommended.
  1066. * @return array
  1067. */
  1068. function getAllTagsCount($exclude_unassigned = false, $checkaccess = false) {
  1069. global $_zp_count_tags;
  1070. if (!is_null($_zp_count_tags)) {
  1071. return $_zp_count_tags;
  1072. }
  1073. if(zp_loggedin(VIEW_ALL_RIGHTS)) {
  1074. $exclude_unassigned = false;
  1075. $checkaccess = false;
  1076. }
  1077. $_zp_count_tags = array();
  1078. $sql = "SELECT DISTINCT tags.name, tags.id, (SELECT COUNT(*) FROM " . prefix('obj_to_tag') . " as object WHERE object.tagid = tags.id) AS count FROM " . prefix('tags') . " as tags ORDER BY `name`";
  1079. $tagresult = query($sql);
  1080. if ($tagresult) {
  1081. while ($tag = db_fetch_assoc($tagresult)) {
  1082. if($checkaccess) {
  1083. $count = getTagCountByAccess($tag);
  1084. if($count != 0) {
  1085. $_zp_count_tags[$tag['name']] = $count;
  1086. }
  1087. } else {
  1088. if($exclude_unassigned) {
  1089. if($tag['count'] != 0) {
  1090. $_zp_count_tags[$tag['name']] = $tag['count'];
  1091. }
  1092. } else {
  1093. $_zp_count_tags[$tag['name']] = $tag['count'];
  1094. }
  1095. }
  1096. }
  1097. db_free_result($tagresult);
  1098. }
  1099. return $_zp_count_tags;
  1100. }
  1101. /**
  1102. * Checks if a tag is assigned at all and if it can be viewed by the current visitor and returns the corrected count
  1103. * Helper function used optionally within getAllTagsCount() and getAllTagsUnique()
  1104. *
  1105. * @global obj $_zp_zenpage
  1106. * @param array $tag Array representing a tag containing at least its name and id
  1107. * @return int
  1108. */
  1109. function getTagCountByAccess($tag) {
  1110. global $_zp_zenpage, $_zp_object_to_tags;
  1111. if (array_key_exists('count', $tag) && $tag['count'] == 0) {
  1112. return $tag['count'];
  1113. }
  1114. $hidealbums = getNotViewableAlbums();
  1115. $hideimages = getNotViewableImages();
  1116. $hidenews = array();
  1117. $hidepages = array();
  1118. if (extensionEnabled('Zenpage')) {
  1119. $hidenews = $_zp_zenpage->getNotViewableNews();
  1120. $hidepages = $_zp_zenpage->getNotViewablePages();
  1121. }
  1122. //skip checks if there are no unviewable items at all
  1123. if (empty($hidealbums) && empty($hideimages) && empty($hidenews) && empty($hidepages)) {
  1124. if (array_key_exists('count', $tag)) {
  1125. return $tag['count'];
  1126. }
  1127. return 0;
  1128. }
  1129. if (is_null($_zp_object_to_tags)) {
  1130. $sql = "SELECT tagid, type, objectid FROM " . prefix('obj_to_tag') . " ORDER BY tagid";
  1131. $_zp_object_to_tags = query_full_array($sql);
  1132. }
  1133. $count = '';
  1134. if ($_zp_object_to_tags) {
  1135. foreach($_zp_object_to_tags as $tagcheck) {
  1136. if ($tagcheck['tagid'] == $tag['id']) {
  1137. switch ($tagcheck['type']) {
  1138. case 'albums':
  1139. if (!in_array($tagcheck['objectid'], $hidealbums)) {
  1140. $count++;
  1141. }
  1142. break;
  1143. case 'images':
  1144. if (!in_array($tagcheck['objectid'], $hideimages)) {
  1145. $count++;
  1146. }
  1147. break;
  1148. case 'news':
  1149. if (extensionEnabled('Zenpage') && ZP_NEWS_ENABLED) {
  1150. if (!in_array($tagcheck['objectid'], $hidenews)) {
  1151. $count++;
  1152. }
  1153. }
  1154. break;
  1155. case 'pages':
  1156. if (extensionEnabled('Zenpage') && ZP_PAGES_ENABLED) {
  1157. if (!in_array($tagcheck['objectid'], $hidepages)) {
  1158. $count++;
  1159. }
  1160. }
  1161. break;
  1162. }
  1163. }
  1164. }
  1165. }
  1166. if (empty($count)) {
  1167. $count = 0;
  1168. }
  1169. return $count;
  1170. }
  1171. /**
  1172. * Stores tags for an object
  1173. *
  1174. * @param array $tags the tag values
  1175. * @param int $id the record id of the album/image
  1176. * @param string $tbl database table of the object
  1177. */
  1178. function storeTags($tags, $id, $tbl) {
  1179. if ($id) {
  1180. $tagsLC = array();
  1181. foreach ($tags as $key => $tag) {
  1182. $tag = trim($tag);
  1183. if (!empty($tag)) {
  1184. $lc_tag = mb_strtolower($tag);
  1185. if (!in_array($lc_tag, $tagsLC)) {
  1186. $tagsLC[$tag] = $lc_tag;
  1187. }
  1188. }
  1189. }
  1190. $sql = "SELECT `id`, `tagid` from " . prefix('obj_to_tag') . " WHERE `objectid`='" . $id . "' AND `type`='" . $tbl . "'";
  1191. $result = query($sql);
  1192. $existing = array();
  1193. if ($result) {
  1194. while ($row = db_fetch_assoc($result)) {
  1195. $dbtag = query_single_row("SELECT `name` FROM " . prefix('tags') . " WHERE `id`='" . $row['tagid'] . "'");
  1196. $existingLC = mb_strtolower($dbtag['name']);
  1197. if (in_array($existingLC, $tagsLC)) { // tag already set no action needed
  1198. $existing[] = $existingLC;
  1199. } else { // tag no longer set, remove it
  1200. query("DELETE FROM " . prefix('obj_to_tag') . " WHERE `id`='" . $row['id'] . "'");
  1201. }
  1202. }
  1203. db_free_result($result);
  1204. }
  1205. $tags = array_diff($tagsLC, $existing); // new tags for the object
  1206. foreach ($tags as $key => $tag) {
  1207. $dbtag = query_single_row("SELECT `id` FROM " . prefix('tags') . " WHERE `name`=" . db_quote($key));
  1208. if (!is_array($dbtag)) { // tag does not exist
  1209. query("INSERT INTO " . prefix('tags') . " (name) VALUES (" . db_quote($key) . ")", false);
  1210. $dbtag = array('id' => db_insert_id());
  1211. }
  1212. query("INSERT INTO " . prefix('obj_to_tag') . "(`objectid`, `tagid`, `type`) VALUES (" . $id . "," . $dbtag['id'] . ",'" . $tbl . "')");
  1213. }
  1214. }
  1215. }
  1216. /**
  1217. * Retrieves the tags for an object
  1218. * Returns them in an array
  1219. *
  1220. * @param int $id the record id of the album/image
  1221. * @param string $tbl 'albums' or 'images', etc.
  1222. * @return unknown
  1223. */
  1224. function readTags($id, $tbl) {
  1225. $tags = array();
  1226. $result = query("SELECT `tagid` FROM " . prefix('obj_to_tag') . " WHERE `type`='" . $tbl . "' AND `objectid`='" . $id . "'");
  1227. if ($result) {
  1228. while ($row = db_fetch_assoc($result)) {
  1229. $dbtag = query_single_row("SELECT `name` FROM" . prefix('tags') . " WHERE `id`='" . $row['tagid'] . "'");
  1230. if ($dbtag) {
  1231. $tags[] = $dbtag['name'];
  1232. }
  1233. }
  1234. db_free_result($result);
  1235. }
  1236. natcasesort($tags);
  1237. return $tags;
  1238. }
  1239. /**
  1240. * Creates the body of a select list
  1241. *
  1242. * @param array $currentValue list of items to be flagged as checked
  1243. * @param array $list the elements of the select list
  1244. * @param bool $descending set true for a reverse order sort
  1245. */
  1246. function generateListFromArray($currentValue, $list, $descending, $localize) {
  1247. if ($localize) {
  1248. $list = array_flip($list);
  1249. if ($descending) {
  1250. arsort($list);
  1251. } else {
  1252. natcasesort($list);
  1253. }
  1254. $list = array_flip($list);
  1255. } else {
  1256. if ($descending) {
  1257. rsort($list);
  1258. } else {
  1259. natcasesort($list);
  1260. }
  1261. }
  1262. foreach ($list as $key => $item) {
  1263. echo '<option value="' . html_encode($item) . '"';
  1264. if (in_array($item, $currentValue)) {
  1265. echo ' selected="selected"';
  1266. }
  1267. if ($localize)
  1268. $display = $key;
  1269. else
  1270. $display = $item;
  1271. echo '>' . $display . "</option>" . "\n";
  1272. }
  1273. }
  1274. /**
  1275. * Generates a selection list from files found on disk
  1276. *
  1277. * @param strig $currentValue the current value of the selector
  1278. * @param string $root directory path to search
  1279. * @param string $suffix suffix to select for
  1280. * @param bool $descending set true to get a reverse order sort
  1281. */
  1282. function generateListFromFiles($currentValue, $root, $suffix, $descending = false) {
  1283. if (is_dir($root)) {
  1284. $curdir = getcwd();
  1285. chdir($root);
  1286. $filelist = safe_glob('*' . $suffix);
  1287. $list = array();
  1288. foreach ($filelist as $file) {
  1289. $file = str_replace($suffix, '', $file);
  1290. $list[] = filesystemToInternal($file);
  1291. }
  1292. generateListFromArray(array($currentValue), $list, $descending, false);
  1293. chdir($curdir);
  1294. }
  1295. }
  1296. /**
  1297. * @param string $url The link URL
  1298. * @param string $text The text to go with the link
  1299. * @param string $title Text for the title tag
  1300. * @param string $class optional class
  1301. * @param string $id optional id
  1302. */
  1303. function getLinkHTML($url, $text, $title = NULL, $class = NULL, $id = NULL) {
  1304. return "<a href=\"" . html_encode($url) . "\"" .
  1305. (($title) ? " title=\"" . html_encode(getBare($title)) . "\"" : "") .
  1306. (($class) ? " class=\"$class\"" : "") .
  1307. (($id) ? " id=\"$id\"" : "") . ">" .
  1308. html_encode($text) . "</a>";
  1309. }
  1310. /**
  1311. * General link printing function
  1312. * @param string $url The link URL
  1313. * @param string $text The text to go with the link
  1314. * @param string $title Text for the title tag
  1315. * @param string $class optional class
  1316. * @param string $id optional id
  1317. */
  1318. function printLinkHTML($url, $text, $title = NULL, $class = NULL, $id = NULL) {
  1319. echo getLinkHTML($url, $text, $title, $class, $id);
  1320. }
  1321. /**
  1322. * shuffles an array maintaining the keys
  1323. *
  1324. * @param array $array
  1325. * @return boolean
  1326. */
  1327. function shuffle_assoc(&$array) {
  1328. $keys = array_keys($array);
  1329. shuffle($keys);
  1330. foreach ($keys as $key) {
  1331. $new[$key] = $array[$key];
  1332. }
  1333. $array = $new;
  1334. return true;
  1335. }
  1336. /**
  1337. * sorts the found albums (images) by the required key(s)
  1338. *
  1339. * NB: this sort is sensitive to the key(s) chosen and makes
  1340. * the appropriate sorts based on same. Some multi-key sorts
  1341. * will not make any sense and will give unexpected results.
  1342. * Most notably any that contain the keys "title" or "desc"
  1343. * as these require multi-lingual sorts.
  1344. *
  1345. * @param array $results
  1346. * @param string $sortkey
  1347. * @param string $order
  1348. */
  1349. function sortByKey($results, $sortkey, $order) {
  1350. $sortkey = str_replace('`', '', $sortkey);
  1351. switch ($sortkey) {
  1352. case 'title':
  1353. case 'desc':
  1354. return sortByMultilingual($results, $sortkey, $order);
  1355. case 'RAND()':
  1356. shuffle($results);
  1357. return $results;
  1358. default:
  1359. if (preg_match('`[\/\(\)\*\+\-!\^\%\<\>\=\&\|]`', $sortkey)) {
  1360. return $results; // We cannot deal with expressions
  1361. }
  1362. }
  1363. $indicies = explode(',', $sortkey);
  1364. foreach ($indicies as $key => $index) {
  1365. $indicies[$key] = trim($index);
  1366. }
  1367. $results = sortMultiArray($results, $indicies, $order, true, false, true);
  1368. return $results;
  1369. }
  1370. /**
  1371. * multidimensional array column sort
  1372. *
  1373. * @param array $array The multidimensional array to be sorted
  1374. * @param mixed $index Which key(s) should be sorted by
  1375. * @param string $order true for descending sorts
  1376. * @param bool $natsort If natural order should be used
  1377. * @param bool $case_sensitive If the sort should be case sensitive
  1378. * @return array
  1379. *
  1380. * @author redoc (http://codingforums.com/showthread.php?t=71904)
  1381. */
  1382. function sortMultiArray($array, $index, $descending = false, $natsort = true, $case_sensitive = false, $preservekeys = false, $remove_criteria = array()) {
  1383. if (is_array($array) && count($array) > 0) {
  1384. if (is_array($index)) {
  1385. $indicies = $index;
  1386. } else {
  1387. $indicies = array($index);
  1388. }
  1389. if ($descending) {
  1390. $separator = '~~';
  1391. } else {
  1392. $separator = ' ';
  1393. }
  1394. foreach ($array as $key => $row) {
  1395. $temp[$key] = '';
  1396. foreach ($indicies as $index) {
  1397. if (is_array($row) && array_key_exists($index, $row)) {
  1398. $temp[$key] .= get_language_string($row[$index]) . $separator;
  1399. if (in_array($index, $remove_criteria)) {
  1400. unset($array[$key][$index]);
  1401. }
  1402. }
  1403. }
  1404. $temp[$key] .= $key;
  1405. }
  1406. if ($natsort) {
  1407. if ($case_sensitive) {
  1408. natsort($temp);
  1409. } else {
  1410. natcasesort($temp);
  1411. }
  1412. if ($descending) {
  1413. $temp = array_reverse($temp, TRUE);
  1414. }
  1415. } else {
  1416. if ($descending) {
  1417. arsort($temp);
  1418. } else {
  1419. asort($temp);
  1420. }
  1421. }
  1422. foreach (array_keys($temp) as $key) {
  1423. if (!$preservekeys && is_numeric($key)) {
  1424. $sorted[] = $array[$key];
  1425. } else {
  1426. $sorted[$key] = $array[$key];
  1427. }
  1428. }
  1429. return $sorted;
  1430. }
  1431. return $array;
  1432. }
  1433. /**
  1434. * Returns a list of album IDs that the current viewer is not allowed to see
  1435. *
  1436. * @return array
  1437. */
  1438. function getNotViewableAlbums() {
  1439. global $_zp_not_viewable_album_list;
  1440. if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS))
  1441. return array(); //admins can see all
  1442. if (is_null($_zp_not_viewable_album_list)) {
  1443. $sql = 'SELECT `folder`, `id`, `password`, `show` FROM ' . prefix('albums') . ' WHERE `show`=0 OR `password`!=""';
  1444. $result = query($sql);
  1445. if ($result) {
  1446. $_zp_not_viewable_album_list = array();
  1447. while ($row = db_fetch_assoc($result)) {
  1448. if (checkAlbumPassword($row['folder'])) {
  1449. $album = newAlbum($row['folder']);
  1450. if (!($row['show'] || $album->isMyItem(LIST_RIGHTS))) {
  1451. $_zp_not_viewable_album_list[] = $row['id'];
  1452. }
  1453. } else {
  1454. $_zp_not_viewable_album_list[] = $row['id'];
  1455. }
  1456. }
  1457. db_free_result($result);
  1458. }
  1459. }
  1460. return $_zp_not_viewable_album_list;
  1461. }
  1462. /**
  1463. * Returns a list of image IDs that the current viewer is not allowed to see
  1464. *
  1465. * @return array
  1466. */
  1467. function getNotViewableImages() {
  1468. global $_zp_not_viewable_image_list;
  1469. if (zp_loggedin(ADMIN_RIGHTS | MANAGE_ALL_ALBUM_RIGHTS)) {
  1470. return array(); //admins can see all
  1471. }
  1472. $hidealbums = getNotViewableAlbums();
  1473. $where = '';
  1474. if (!is_null($hidealbums)) {
  1475. $where = implode(',', $hidealbums);
  1476. }
  1477. if (is_null($_zp_not_viewable_image_list)) {
  1478. $sql = 'SELECT DISTINCT `id` FROM ' . prefix('images') . ' WHERE `show` = 0 OR `albumid` in (' . $where . ')';
  1479. $result = query($sql);
  1480. if ($result) {
  1481. $_zp_not_viewable_image_list = array();
  1482. while ($row = db_fetch_assoc($result)) {
  1483. $_zp_not_viewable_image_list[] = $row['id'];
  1484. }
  1485. }
  1486. }
  1487. return $_zp_not_viewable_image_list;
  1488. }
  1489. /**
  1490. * Checks to see if a URL is valid
  1491. *
  1492. * @param string $url the URL being checked
  1493. * @return bool
  1494. */
  1495. function isValidURL($url) {
  1496. return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $url);
  1497. }
  1498. /**
  1499. * pattern match function Works with characters with diacritical marks where the PHP one does not.
  1500. *
  1501. * @param string $pattern pattern
  1502. * @param string $string haystack
  1503. * @return bool
  1504. */
  1505. function safe_fnmatch($pattern, $string) {
  1506. return @preg_match('/^' . strtr(addcslashes($pattern, '\\.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string);
  1507. }
  1508. /**
  1509. * returns a list of comment record 'types' for "images"
  1510. * @param string $quote quotation mark to use
  1511. *
  1512. * @return string
  1513. */
  1514. function zp_image_types($quote) {
  1515. global $_zp_extra_filetypes;
  1516. $typelist = $quote . 'images' . $quote . ',' . $quote . '_images' . $quote . ',';
  1517. $types = array_unique($_zp_extra_filetypes);
  1518. foreach ($types as $type) {
  1519. $typelist .= $quote . strtolower($type) . 's' . $quote . ',';
  1520. }
  1521. return substr($typelist, 0, -1);
  1522. }
  1523. /**
  1524. * Returns video argument of the current Image.
  1525. *
  1526. * @param object $image optional image object
  1527. * @return bool
  1528. */
  1529. function isImageVideo($image = NULL) {
  1530. if (is_null($image)) {
  1531. if (!in_context(ZP_IMAGE))
  1532. return false;
  1533. global $_zp_current_image;
  1534. $image = $_zp_current_image;
  1535. }
  1536. return strtolower(get_class($image)) == 'video';
  1537. }
  1538. /**
  1539. * Returns true if the image is a standard photo type
  1540. *
  1541. * @param object $image optional image object
  1542. * @return bool
  1543. */
  1544. function isImagePhoto($image = NULL) {
  1545. if (is_null($image)) {
  1546. if (!in_context(ZP_IMAGE))
  1547. return false;
  1548. global $_zp_current_image;
  1549. $image = $_zp_current_image;
  1550. }
  1551. $class = strtolower(get_class($image));
  1552. return $class == 'image' || $class == 'transientimage';
  1553. }
  1554. /**
  1555. * Copies a directory recursively
  1556. * @param string $srcdir the source directory.
  1557. * @param string $dstdir the destination directory.
  1558. * @return the total number of files copied.
  1559. */
  1560. function dircopy($srcdir, $dstdir) {
  1561. $num = 0;
  1562. if (!is_dir($dstdir))
  1563. mkdir($dstdir);
  1564. if ($curdir = opendir($srcdir)) {
  1565. while ($file = readdir($curdir)) {
  1566. if ($file != '.' && $file != '..') {
  1567. $srcfile = $srcdir . '/' . $file;
  1568. $dstfile = $dstdir . '/' . $file;
  1569. if (is_file($srcfile)) {
  1570. if (is_file($dstfile))
  1571. $ow = filemtime($srcfile) - filemtime($dstfile);
  1572. else
  1573. $ow = 1;
  1574. if ($ow > 0) {
  1575. if (copy($srcfile, $dstfile)) {