PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/zina/common.php

https://bitbucket.org/helmespc/zina2
PHP | 1126 lines | 920 code | 101 blank | 105 comment | 152 complexity | 1f8a0875df35ba45dd04fd4092012ea5 MD5 | raw file
  1. <?php
  2. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3. * ZINA2 (Zina2 is not Zina)
  4. *
  5. * Zina2 is a graphical interface to your MP3 collection, a personal
  6. * jukebox, an MP3 streamer. It can run on its own, embeded into an
  7. * existing website, or as a Drupal/Joomla/Wordpress/etc. module.
  8. *
  9. * https://bitbucket.org/helmespc/zina2
  10. * Author: Patrick Helmes <helmespc@gmail.com>
  11. * Support: https://bitbucket.org/helmespc/zina2/wiki/Home
  12. * License: GNU GPL2 <http://www.gnu.org/copyleft/gpl.html>
  13. *
  14. * This Software is a fork of Zina (is not Andromeda):
  15. * http://www.pancake.org/zina
  16. * Author: Ryan Lathouwers <ryanlath@pacbell.net>
  17. * Support: http://sourceforge.net/projects/zina/
  18. * License: GNU GPL2 <http://www.gnu.org/copyleft/gpl.html>
  19. *
  20. * common.php
  21. * - common functions (many modified/inspired from Drupal)
  22. *
  23. * TODO:
  24. * - normalize function names
  25. * - organize file
  26. *
  27. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  28. /**************************************************
  29. Description:
  30. This function translates a string based on
  31. the globally defined language setting.
  32. Returns:
  33. - The translated string, if the translation was
  34. successful.
  35. - If the translation was unsuccessful, the
  36. original string is returned.
  37. Usage Notes:
  38. **************************************************/
  39. function zt($string, $args = array()) {
  40. global $zina_lang_code, $zina_lang_path;
  41. static $lang;
  42. // Load the language file (i.e. $lang['fr'])
  43. if (!isset($lang[$zina_lang_code]) && $zina_lang_path) {
  44. $lang[$zina_lang_code] = array();
  45. include($zina_lang_path);
  46. }
  47. // Find input string in the language array
  48. if (isset($lang[$zina_lang_code][$string])) {
  49. $string = $lang[$zina_lang_code][$string];
  50. }
  51. // If the args value is empty or invalid, return the original
  52. // string.
  53. if (empty($args) || !is_array($args)) {
  54. return $string;
  55. }
  56. // Transform arguments before inserting them.
  57. foreach ($args as $key => $value) {
  58. switch ($key[0]) {
  59. case '@':
  60. // Escaped only.
  61. $args[$key] = zcheck_plain($value);
  62. break;
  63. case '%':
  64. default:
  65. // Escaped and placeholder.
  66. $args[$key] = ztheme('placeholder', $value);
  67. break;
  68. case '!':
  69. // Pass-through.
  70. }
  71. }
  72. return strtr($string, $args);
  73. }
  74. function zcheck_plain($text) {
  75. if (zvalidate_utf8($text)) {
  76. return htmlspecialchars($text, ENT_QUOTES);
  77. }
  78. else {
  79. global $zc;
  80. return ((strtolower($zc['charset']) == 'utf-8') ? utf8_encode($text) : '');
  81. }
  82. }
  83. function zcheck_utf8($text, $xml=true) {
  84. global $zc;
  85. # Best so far???
  86. return (!(preg_match('/^./us', $text) == 1) && strtolower($zc['charset']) == 'utf-8') ? utf8_encode($text) : (($xml) ? zxml_encode($text) : $text);
  87. #return (!zvalidate_utf8($text) && strtolower($zc['charset']) == 'utf-8') ? utf8_encode($text) : (($xml) ? zxml_encode($text) : $text);
  88. }
  89. function zvalidate_utf8($text) {
  90. // If the strlen is 0, valid UTF8
  91. if (strlen($text) == 0) {
  92. return true;
  93. }
  94. // Validate against a regex match
  95. return (preg_match('/^./us', $text) == 1);
  96. }
  97. function zina_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
  98. if ($message) {
  99. if (!isset($_SESSION['messages'])) {
  100. $_SESSION['messages'] = array();
  101. }
  102. if (!isset($_SESSION['messages'][$type])) {
  103. $_SESSION['messages'][$type] = array();
  104. }
  105. if ($repeat || !in_array($message, $_SESSION['messages'][$type])) {
  106. $_SESSION['messages'][$type][] = $message;
  107. }
  108. }
  109. // messages not set when DB connection fails
  110. return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL;
  111. }
  112. function zina_get_messages($type = NULL, $clear_queue = TRUE) {
  113. if ($messages = zina_set_message()) {
  114. if ($type) {
  115. if ($clear_queue) {
  116. unset($_SESSION['messages'][$type]);
  117. }
  118. if (isset($messages[$type])) {
  119. return array($type => $messages[$type]);
  120. }
  121. }
  122. else {
  123. if ($clear_queue) {
  124. unset($_SESSION['messages']);
  125. }
  126. return $messages;
  127. }
  128. }
  129. return array();
  130. }
  131. function ztheme() {
  132. global $zc;
  133. $args = func_get_args();
  134. $function = array_shift($args);
  135. if (function_exists($zc['theme'].'_'.$function)) {
  136. return call_user_func_array($zc['theme'].'_'.$function, $args);
  137. } elseif (function_exists('ztheme_'. $function)){
  138. return call_user_func_array('ztheme_'.$function, $args);
  139. }
  140. }
  141. #todo: change to drupal 6? arr of $opts??
  142. function zurl($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE, $direct = FALSE) {
  143. global $zc;
  144. if (isset($fragment)) $fragment = '#'. $fragment;
  145. // Return an external link
  146. if (strpos($path, ':') !== FALSE) {
  147. // Split off the fragment
  148. if (strpos($path, '#') !== FALSE) {
  149. list($path, $old_fragment) = explode('#', $path, 2);
  150. if (isset($old_fragment) && !isset($fragment)) $fragment = '#'. $old_fragment;
  151. }
  152. if (isset($query)) $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $query;
  153. return $path.$fragment;
  154. }
  155. #todo: base_path not set?
  156. static $script, $base_url, $base_path, $base_url2, $base_path2, $www_path;
  157. if (!isset($script)) {
  158. $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE && !$zc['clean_urls']) ? 'index.php' : '';
  159. }
  160. if (!isset($base_url)) {
  161. $base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
  162. $base_url = $base_root .= '://'.$zc['auth']. preg_replace('/[^a-z0-9-:._]/i', '', $_SERVER['HTTP_HOST']);
  163. }
  164. if ($direct) {
  165. $base = ($absolute) ? $base_url : '';
  166. if (!isset($www_path)) {
  167. $tmp = preg_replace("#^${_SERVER['DOCUMENT_ROOT']}#i", '', $zc['mp3_dir'], -1, $count);
  168. $www_path = ($count > 0) ? $tmp : '';
  169. }
  170. return $base.$www_path.'/'.zrawurlencode($path);
  171. } else {
  172. if (!isset($base_url2)) {
  173. if ($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) {
  174. $base_path2 = "/$dir";
  175. $base_url2 = $base_url.$base_path2;
  176. $base_path2 .= '/';
  177. } else {
  178. $base_path2 = '/';
  179. $base_url2 = $base_url;
  180. }
  181. if (isset($zc['index_rel'])) {
  182. $base_url2 .= '/'.$zc['index_rel'];
  183. $base_path2 .= $zc['index_rel'] .'/';
  184. }
  185. }
  186. $base = ($absolute) ? $base_url2 . '/' : $base_path2;
  187. }
  188. if (isset($zc['url_query'])) {
  189. $url_query = implode('&',$zc['url_query']);
  190. $query .= (empty($query)) ? $url_query : '&'.$url_query;
  191. }
  192. if (!empty($path)) {
  193. if ($zc['clean_urls']) {
  194. $path = str_replace(array('%2F', '%26', '%23', '//', '%2B'), array('/', '%2526', '%2523', '/%252F', '%252B'), rawurlencode($path));
  195. return $base.$path.((isset($query)) ? '?'.$query:'').$fragment;
  196. } else {
  197. $path = str_replace('%2F', '/', rawurlencode($path));
  198. return $base.$script.'?p='.$path.(isset($query)?'&'.$query:'').$fragment;
  199. }
  200. } else {
  201. return $base.(isset($query)?$script.'?'.$query:'').$fragment;
  202. }
  203. }
  204. function zrawurlencode($path) {
  205. return str_replace(array('%2F', '%26', '%23'), array('/', '%2526', '%2523'), rawurlencode($path));
  206. }
  207. function zrawurldecode($x) {
  208. return str_replace(array('%2F', '%26', '%23'), array('/', '&', '#'), rawurldecode($x));
  209. }
  210. function zpath_to_theme($path_rel = null) {
  211. static $theme_dir;
  212. if (!empty($path_rel)) $theme_dir = $path_rel;
  213. return $theme_dir;
  214. }
  215. /*
  216. #TODO: redo ala D6
  217. function zl($text, $path, $options = array()) {
  218. $options += array(
  219. 'attributes' => array(),
  220. 'html' => FALSE,
  221. );
  222. if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
  223. $options['attributes']['title'] = strip_tags($options['attributes']['title']);
  224. }
  225. return '<a href="' . check_plain(url($path, $options)) . '"' . drupal_attributes($options['attributes']) . '>' . ($options['html'] ? $text : check_plain($text)) . '</a>';
  226. }
  227. */
  228. function zl($text, $path, $query = NULL, $fragment = NULL, $absolute = FALSE, $attributes = '') {
  229. if (!empty($attributes)) $attributes = ' '.$attributes;
  230. return '<a href="'.zurl($path, $query, $fragment, $absolute).'"'.$attributes.'>'.$text.'</a>';
  231. }
  232. function zina_get_headers() {
  233. foreach(zina_set_header() as $header) {
  234. header($header);
  235. }
  236. }
  237. function zina_set_header($header = NULL) {
  238. static $stored_headers = array();
  239. if (strlen($header)) {
  240. $stored_headers[] = $header;
  241. }
  242. return $stored_headers;
  243. }
  244. function zina_set_html_head($header = NULL) {
  245. static $headers = array();
  246. if (strlen($header)) {
  247. $headers[$header] = true;
  248. }
  249. return $headers;
  250. }
  251. function zina_get_html_head() {
  252. return implode("\n", array_keys(zina_set_html_head()));
  253. }
  254. # type = inline or file
  255. function zina_set_css($type = null, $css = null) {
  256. global $zc;
  257. static $files = array(), $inline = '';
  258. if (empty($files)) {
  259. $files['themes/'.$zc['theme'].'/common.css'] = true;
  260. }
  261. if (empty($type)) {
  262. $output = '';
  263. $files = array_reverse($files);
  264. foreach ($files as $file => $nothing) {
  265. $output .= '<link rel="stylesheet" href="'.$zc['zina_dir_rel'].'/'.$file.'" type="text/css" />'."\n";
  266. }
  267. if (!empty($inline)) $output .= '<style type="text/css">'.$inline.'</style>'."\n";
  268. return $output;
  269. } else {
  270. if ($type == 'file')
  271. $files[$css] = true;
  272. elseif ($type == 'inline')
  273. $inline .= $css;
  274. }
  275. }
  276. function zina_get_js() {
  277. global $zc;
  278. $js = zina_set_js();
  279. $output = '';
  280. foreach($js['file'] as $file=> $relative) {
  281. $path = ($relative) ? $zc['zina_dir_rel'].'/' : '';
  282. $output .= '<script type="text/javascript" src="'.$path.$file.'"></script>'."\n";
  283. }
  284. #for validation
  285. $prefix = "\n<!--//--><![CDATA[//><!--\n";
  286. $suffix = "\n//--><!]]>\n";
  287. if (!empty($js['inline']) || !empty($js['jquery']) || !empty($js['vars'])) {
  288. $output .= '<script type="text/javascript">'.$prefix;
  289. if (!empty($js['vars'])) $output .= implode('', $js['vars']);
  290. if (!empty($js['jquery'])) {
  291. $noconflict = (!in_array($zc['embed'], array('standalone', 'drupal'))) ? 'jQuery.noConflict();' : '';
  292. $output .= $noconflict.'jQuery(document).ready(function($){'.implode('', $js['jquery']).'});';
  293. }
  294. if (!empty($js['inline'])) $output .= implode('', $js['inline']);
  295. $output .= $suffix.'</script>';
  296. }
  297. return $output;
  298. }
  299. # type = inline or file
  300. function zina_set_js($type = null, $js = null, $relative = true) {
  301. static $javascript = array();
  302. if (empty($files)) $javascript['file']['zina.js'] = true;
  303. if ($type == 'file')
  304. $javascript['file'][$js] = $relative;
  305. elseif ($type == 'vars')
  306. $javascript['vars'][] = $js;
  307. elseif ($type == 'jquery')
  308. $javascript['jquery'][] = $js;
  309. else
  310. $javascript['inline'][] = $js;
  311. return $javascript;
  312. }
  313. function zo_shuffle(&$array){
  314. $last = count($array);
  315. while ($last > 0){
  316. $last--;
  317. $random = mt_rand(0, $last);
  318. $temp = $array[$random];
  319. $array[$random] = $array[$last];
  320. $array[$last] = $temp;
  321. }
  322. return 1;
  323. }
  324. /*
  325. * Gets serialized content or converts from older format
  326. */
  327. function zunserialize_alt($content) {
  328. if (($array = @unserialize($content)) === false) {
  329. $array = explode("\n", rtrim($content,"\r\n"));
  330. foreach($array as $key=>$val) {
  331. $array[$key] = rtrim($val,"\r\n");
  332. }
  333. }
  334. return $array;
  335. }
  336. function unserialize_utf8($text) {
  337. if (empty($text)) return false;
  338. $output = @unserialize(utf8_decode($text));
  339. if ($output === false) {
  340. $output = unserialize(preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $text));
  341. }
  342. return $output;
  343. }
  344. function zina_goto($path = '', $query = null, $fragment = null, $absolute = false, $direct = false, $exit_on_done = true) {
  345. $url = zurl($path, $query, $fragment, $absolute, $direct);
  346. $url = str_replace(array("\n", "\r"), '', $url);
  347. @session_write_close();
  348. while(@ob_end_clean());
  349. header('Location: '. $url, TRUE, 302);
  350. if ($exit_on_done) {
  351. exit();
  352. }
  353. }
  354. function zina_debug($error, $level='warn') {
  355. global $zc;
  356. if ($zc['debug']) {
  357. zina_set_message($error, $level);
  358. error_log('Zina '.$level.': '.$error);
  359. }
  360. }
  361. function zina_check_directory($directory, $create = 0) {
  362. global $zc;
  363. $directory = rtrim($directory, '/\\');
  364. if (!is_dir($directory)) {
  365. if ($create) {
  366. if (@mkdir($directory)) {
  367. zina_set_message(zt('The directory %directory has been created.', array('%directory' => $directory)));
  368. @chmod($directory, 0775); // Necessary for non-webserver users.
  369. } else {
  370. zina_set_message(zt('Cannot create directory %directory.', array('%directory' => $directory)),'error');
  371. return FALSE;
  372. }
  373. } else {
  374. zina_set_message(zt('Directory does not exist %directory.', array('%directory' => $directory)),'error');
  375. return FALSE;
  376. }
  377. }
  378. // Check to see if the directory is writable.
  379. if (!is_writable($directory)) {
  380. if ($mode && @chmod($directory, 0775)) {
  381. zina_set_message(zt('The permissions of directory %directory have been changed to make it writable.', array('%directory' => $directory)));
  382. } else {
  383. zina_set_message(zt('The directory %directory is not writeable.', array('%directory' => $directory)),'error');
  384. return FALSE;
  385. }
  386. }
  387. if ($zc['cache_dir_private_abs'] == $directory && !is_file("$directory/.htaccess")) {
  388. $htaccess_lines = "Options None\nOrder Deny,Allow\nDeny from all";
  389. if (($fp = fopen("$directory/.htaccess", 'w')) && fputs($fp, $htaccess_lines)) {
  390. fclose($fp);
  391. chmod($directory .'/.htaccess', 0664);
  392. } else {
  393. $variables = array('%directory' => $directory, '!htaccess' => '<br />'. nl2br(zcheck_plain($htaccess_lines)));
  394. zina_set_message(zt("Security warning: Couldn't write .htaccess file. Please create a .htaccess file in your %directory directory which contains the following lines: <code>!htaccess</code>", $variables),'warn');
  395. }
  396. }
  397. return true;
  398. }
  399. function zina_strlen($text) {
  400. global $zc;
  401. return ($zc['multibyte']) ? mb_strlen($text) : strlen(preg_replace("/[\x80-\xBF]/", '', $text));
  402. }
  403. function zina_substr($text, $start, $length = NULL) {
  404. global $zc;
  405. if ($zc['multibyte']) {
  406. return $length === NULL ? mb_substr($text, $start) : mb_substr($text, $start, $length);
  407. } else {
  408. # NOT a work-around
  409. return $length === NULL ? substr($text, $start) : substr($text, $start, $length);
  410. }
  411. }
  412. function zina_strtoupper($text) {
  413. global $zc;
  414. # NO NON-MB work-around
  415. return ($zc['multibyte']) ? mb_strtoupper($text) : strtoupper($text);
  416. }
  417. function zina_date($format, $timestamp) {
  418. $max = strlen($format);
  419. $date = '';
  420. for ($i = 0; $i < $max; $i++) {
  421. $c = $format[$i];
  422. if (strpos('AaDlM', $c) !== FALSE) {
  423. $date .= zt(gmdate($c, $timestamp));
  424. } else if ($c == 'F') {
  425. // Special treatment for long month names: May is both an abbreviation
  426. // and a full month name in English, but other languages have different abbreviations.
  427. $date .= trim(zt('!long-month-name '. gmdate($c, $timestamp), array('!long-month-name' => '')));
  428. } else if (strpos('BdgGhHiIjLmnsStTUwWYyz', $c) !== FALSE) {
  429. $date .= gmdate($c, $timestamp);
  430. } else if ($c == 'r') {
  431. $date .= format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode);
  432. } else if ($c == 'O') {
  433. $date .= sprintf('%s%02d%02d', ($timezone < 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60);
  434. } else if ($c == 'Z') {
  435. $date .= $timezone;
  436. } else if ($c == '\\') {
  437. $date .= $format[++$i];
  438. } else {
  439. $date .= $c;
  440. }
  441. }
  442. return $date;
  443. }
  444. function zina_delete_file($file) {
  445. global $zc;
  446. if (!file_exists($file) || !zfile_check_location($file, $zc['mp3_dir'])) {
  447. zina_set_message(zt('File does not exist: @file', array('@file'=>$file)));
  448. return false;
  449. }
  450. $full_path = substr($file, strlen($zc['mp3_dir'])+1);
  451. $path = dirname($full_path);
  452. $file_name = basename($full_path);
  453. if (unlink($file)) {
  454. if ($zc['database']) {
  455. $id = zdbq_single("SELECT id FROM {files} WHERE path = '%s' AND file = '%s'", array($path, $file_name));
  456. if (!empty($id)) zdb_remove('file', $id);
  457. }
  458. $exts = $zc['song_es_exts'];
  459. $exts[] = $zc['remote_ext'];
  460. $exts[] = $zc['fake_ext'];
  461. $exts[] = 'txt';
  462. foreach($exts as $ext) {
  463. $aux_files[] = preg_replace('/'.$zc['ext_mus'].'$/i', $ext, $file_name);
  464. }
  465. foreach($aux_files as $aux) {
  466. $aux_file = $path.'/'.$aux;
  467. if (file_exists($aux_file)) unlink($aux_file);
  468. }
  469. return $path;
  470. } else {
  471. zina_set_message(zt('Could not delete file: @file', array('@file'=>$file)));
  472. return false;
  473. }
  474. }
  475. function zina_delete_directory($dir) {
  476. if (!file_exists($dir)) return true;
  477. if (!is_dir($dir) || is_link($dir)) return unlink($dir);
  478. foreach (scandir($dir) as $path) {
  479. if ($path == '.' || $path == '..') continue;
  480. $item = $dir.'/'.$path;
  481. if (!zina_delete_directory($item)) {
  482. chmod($item, 0777);
  483. if (!zina_delete_directory($item)) return false;
  484. }
  485. }
  486. return rmdir($dir);
  487. }
  488. function zina_token_sess($value) {
  489. static $key;
  490. if (empty($key)) {
  491. global $zc;
  492. $keyfile = $zc['cache_dir_private_abs'].'/sitekey.txt';
  493. if (file_exists($keyfile)) {
  494. $key = file_get_contents($keyfile);
  495. } else {
  496. zina_debug(zt('Sitekey file does not exist'),'warn');
  497. return false;
  498. }
  499. }
  500. return md5(session_id() . $value . $key);
  501. }
  502. function zina_token_sess_check() {
  503. global $zc;
  504. if (isset($_POST['token']) && !empty($_POST['token']) && $_POST['token'] == zina_token_sess($zc['user_id'])) {
  505. return true;
  506. }
  507. return false;
  508. }
  509. function zsort_date($a, $b) {
  510. if ($a['mtime'] == $b['mtime']) return 0;
  511. return ($a['mtime'] < $b['mtime']) ? -1 : 1;
  512. }
  513. function zsort_date_desc($a, $b) {
  514. if ($a['mtime'] == $b['mtime']) return 0;
  515. return ($a['mtime'] > $b['mtime']) ? -1 : 1;
  516. }
  517. function zsort_trackno($a, $b) {
  518. if ($a['info']->track == $b['info']->track) return 0;
  519. return ((int)$a['info']->track < (int)$b['info']->track) ? -1 : 1;
  520. }
  521. function zsort_ignore($a, $b) {
  522. global $zc;
  523. #return strnatcasecmp(preg_replace('/(^|\/)('.$zc['dir_si_str'].') /i','$1',$a), preg_replace('/(^|\/)('.$zc['dir_si_str'].') /i','$1',$b));
  524. if (strpos($a, '/') || strpos($b, '/')) {
  525. return strnatcasecmp(preg_replace('/^('.$zc['dir_si_str'].') /i','',basename($a)), preg_replace('/^('.$zc['dir_si_str'].') /i','',basename($b)));
  526. } else {
  527. if (strpos($a, ' ') || strpos($b, ' ')) {
  528. return strnatcasecmp(preg_replace('/^('.$zc['dir_si_str'].') /i','',$a), preg_replace('/^('.$zc['dir_si_str'].') /i','',$b));
  529. } else {
  530. return strnatcasecmp($a, $b);
  531. }
  532. }
  533. }
  534. function zsort_title_ignore($a, $b) {
  535. if ($a['person'] || $b['person']) {
  536. $a1 = $a['title'];
  537. $b1 = $b['title'];
  538. if ($a['person'] && ($pos = strripos($a['title'], ' ')) !== false) {
  539. $a1 = substr($a['title'], $pos+1).','.substr($a['title'], 0, $pos);
  540. }
  541. if ($b['person'] && ($pos = strripos($b['title'], ' ')) !== false) {
  542. $b1 = substr($b['title'], $pos+1).','.substr($b['title'], 0, $pos);
  543. }
  544. return zsort_ignore($a1, $b1);
  545. } else {
  546. return zsort_ignore($a['title'], $b['title']);
  547. }
  548. }
  549. function zsort_title($a, $b) {
  550. if ($a['title'] == $b['title']) return 0;
  551. return ($a['title'] < $b['title']) ? -1 : 1;
  552. }
  553. function zina_validate($type, $value, $opts = null) {
  554. if ($type == 'req') {
  555. if (is_array($value)) {
  556. return (!empty($value));
  557. } else {
  558. return strlen($value) > 0;
  559. }
  560. } elseif ($type == 'tf') {
  561. return ($value == 0 || $value == 1);
  562. } elseif ($type == 'int') {
  563. return (is_numeric($value) ? intval($value) == $value : false);
  564. } elseif ($type == 'int_split') {
  565. $ints = explode(',', $value);
  566. foreach($ints as $int) {
  567. if (!zina_validate('int', $int)) return false;
  568. }
  569. return true;
  570. } elseif ($type == 'file_exists') {
  571. return (file_exists($value));
  572. } elseif ($type == 'alpha_numeric') {
  573. return (!preg_match('/\W/', $value));
  574. } elseif ($type == 'path_relative') {
  575. global $zc;
  576. return zina_check_directory($zc['zina_dir_abs'].'/'.$value,1);
  577. } elseif ($type == 'dir_exists') {
  578. return (file_exists($value) && is_dir($value));
  579. } elseif ($type == 'dir_writeable') {
  580. return zina_check_directory($value,1);
  581. } elseif ($type == 'if') {
  582. $key = key($opts);
  583. if (isset($_POST[$key]) && $_POST[$key] == 1) {
  584. return zina_validate(current($opts), $value);
  585. }
  586. return true;
  587. }
  588. return false;
  589. }
  590. /*
  591. * Thanks to: http://tim-ryan.com/labs/parseINI/
  592. */
  593. function zina_parse_ini_string($ini_string) {
  594. $data = array();
  595. $currentSection = '';
  596. foreach (preg_split('/\r\n?|\r?\n/', $ini_string) as $line) {
  597. if (preg_match('/^\s*\[\s*(.*)\s*\]\s*$/', $line, $matches)) {
  598. $currentSection = $matches[1];
  599. } else if (preg_match('/^\s*([^;\s].*?)\s*=\s*([^\s].*?)$/', $line, $matches)) {
  600. $key = preg_replace('/\[\]$/', '', $matches[1]);
  601. $isArray = preg_match('/\[\]$/', $matches[1]);
  602. preg_match('/^"(?:\\.|[^"])*"|^\'(?:[^\']|\\.)*\'|^[^;]+?\s*(?=;|$)/', $matches[2], $matches);
  603. $value = preg_replace('/^(["\'])(.*?)\1?$/', '\2', stripslashes($matches[0]));
  604. if (is_numeric($value))
  605. $value = (float) $value;
  606. else if (strtolower($value) == 'true')
  607. $value = true;
  608. else if (strtolower($value) == 'false')
  609. $value = false;
  610. $section =& $data[$currentSection];
  611. foreach (explode('.', $key) as $level) {
  612. if (isset($section[$level]) && !is_array($section[$level])) {
  613. $section[$level] = array();
  614. }
  615. $section =& $section[$level];
  616. }
  617. $isArray ? $section[] = $value : $section = $value;
  618. }
  619. }
  620. return $data;
  621. }
  622. function xml_to_array($data, $type = 'file') {
  623. $parser = xml_parser_create();
  624. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  625. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  626. xml_parse_into_struct($parser, $data, $values, $tags);
  627. xml_parser_free($parser);
  628. $items = array();
  629. foreach ($tags as $key=>$val) {
  630. if ($key == $type) {
  631. $pairs = $val;
  632. $num = count($pairs);
  633. if ($num > 1) {
  634. $item = null;
  635. for ($i=0; $i < $num; $i+=2) {
  636. $offset = $pairs[$i] + 1;
  637. $len = $pairs[$i + 1] - $offset;
  638. $vs = array_slice($values, $offset, $len);
  639. for ($j=0; $j < count($vs); $j++) {
  640. if (isset($vs[$j]["value"])) {
  641. $item[$vs[$j]["tag"]] = trim($vs[$j]["value"]);
  642. }
  643. }
  644. $items[] = $item;
  645. }
  646. }
  647. } else {
  648. continue;
  649. }
  650. }
  651. return $items;
  652. }
  653. function zfile_check_location($source, $directory = '') {
  654. $check = realpath($source);
  655. if ($check) {
  656. $source = $check;
  657. } else {
  658. // This file does not yet exist
  659. $source = realpath(dirname($source)) .'/'. basename($source);
  660. }
  661. $directory = realpath($directory);
  662. if ($directory && strpos($source, $directory) !== 0) {
  663. return 0;
  664. }
  665. return $source;
  666. }
  667. function zina_add_tabledrag($table_id, $action, $relationship, $group, $subgroup = NULL, $source = NULL, $hidden = TRUE, $limit = 0) {
  668. if (function_exists('drupal_add_tabledrag')) {
  669. return drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgroup, $source, $hidden, $limit);
  670. }
  671. static $js_added = false;
  672. if (!$js_added) {
  673. global $zc;
  674. zina_set_js('file', 'extras/tabledrag.js');
  675. $js_added = TRUE;
  676. if (isset($zc['index_rel'])) {
  677. $data[] = array('basePath' => '/'.$zc['index_rel'].'/');
  678. }
  679. $trans['Drag to re-order'] = zt('Drag to re-order');
  680. $trans['Changes made in this table will not be saved until the form is submitted.'] = zt('Changes made in this table will not be saved until the form is submitted.');
  681. $test = "Drupal.locale={'strings':". zina_to_js($trans) ."};";
  682. zina_set_js('vars', $test);
  683. }
  684. // If a subgroup or source isn't set, assume it is the same as the group.
  685. $target = isset($subgroup) ? $subgroup : $group;
  686. $source = isset($source) ? $source : $target;
  687. $settings['tableDrag'][$table_id][$group][] = array(
  688. 'target' => $target,
  689. 'source' => $source,
  690. 'relationship' => $relationship,
  691. 'action' => $action,
  692. 'hidden' => $hidden,
  693. 'limit' => $limit,
  694. );
  695. $data[] = $settings;
  696. zina_set_js('vars', 'jQuery.extend(Drupal.settings, ' . zina_to_js(call_user_func_array('array_merge_recursive', $data)) . ");");
  697. }
  698. function zina_to_js($var) {
  699. if (function_exists('drupal_to_js')) return drupal_to_js($var);
  700. switch (gettype($var)) {
  701. case 'boolean':
  702. return $var ? 'true' : 'false'; // Lowercase necessary!
  703. case 'integer':
  704. case 'double':
  705. return $var;
  706. case 'resource':
  707. case 'string':
  708. return '"'. str_replace(array("\r", "\n", "<", ">", "&"),
  709. array('\r', '\n', '\x3c', '\x3e', '\x26'),
  710. addslashes($var)) .'"';
  711. case 'array':
  712. // Arrays in JSON can't be associative. If the array is empty or if it
  713. // has sequential whole number keys starting with 0, it's not associative
  714. // so we can go ahead and convert it as an array.
  715. if (empty ($var) || array_keys($var) === range(0, sizeof($var) - 1)) {
  716. $output = array();
  717. foreach ($var as $v) {
  718. $output[] = zina_to_js($v);
  719. }
  720. return '[ '. implode(', ', $output) .' ]';
  721. }
  722. // Otherwise, fall through to convert the array as an object.
  723. case 'object':
  724. $output = array();
  725. foreach ($var as $k => $v) {
  726. $output[] = zina_to_js(strval($k)) .': '. zina_to_js($v);
  727. }
  728. return '{ '. implode(', ', $output) .' }';
  729. default:
  730. return 'null';
  731. }
  732. }
  733. function xml_field($name, $value, $decode = true) {
  734. return '<'.$name.'>'.zxml_encode($value).'</'.$name.'>'."\n";
  735. }
  736. function zxml_encode($x) {
  737. return htmlspecialchars(zdecode_entities($x));
  738. }
  739. function zdecode_entities($text, $exclude = array()) {
  740. static $table;
  741. if (!isset($table)) {
  742. $table = array_flip(get_html_translation_table(HTML_ENTITIES));
  743. $table = array_map('utf8_encode', $table);
  744. $table['&apos;'] = "'";
  745. }
  746. $newtable = (!empty($exclude)) ? array_diff($table, $exclude) : $table;
  747. return preg_replace('/&(#x?)?([A-Za-z0-9]+);/e', '_zdecode_entities("$1", "$2", "$0", $newtable, $exclude)', $text);
  748. }
  749. /**
  750. * Helper function for decode_entities
  751. */
  752. function _zdecode_entities($prefix, $codepoint, $original, &$table, &$exclude) {
  753. if (!$prefix) {
  754. if (isset($table[$original])) {
  755. return $table[$original];
  756. }
  757. else {
  758. return $original;
  759. }
  760. }
  761. if ($prefix == '#x') {
  762. $codepoint = base_convert($codepoint, 16, 10);
  763. } else {
  764. $codepoint = preg_replace('/^0+/', '', $codepoint);
  765. }
  766. if ($codepoint < 0x80) {
  767. $str = chr($codepoint);
  768. } else if ($codepoint < 0x800) {
  769. $str = chr(0xC0 | ($codepoint >> 6))
  770. . chr(0x80 | ($codepoint & 0x3F));
  771. } else if ($codepoint < 0x10000) {
  772. $str = chr(0xE0 | ( $codepoint >> 12))
  773. . chr(0x80 | (($codepoint >> 6) & 0x3F))
  774. . chr(0x80 | ( $codepoint & 0x3F));
  775. } else if ($codepoint < 0x200000) {
  776. $str = chr(0xF0 | ( $codepoint >> 18))
  777. . chr(0x80 | (($codepoint >> 12) & 0x3F))
  778. . chr(0x80 | (($codepoint >> 6) & 0x3F))
  779. . chr(0x80 | ( $codepoint & 0x3F));
  780. }
  781. // Check for excluded characters
  782. if (in_array($str, $exclude)) {
  783. return $original;
  784. } else {
  785. return $str;
  786. }
  787. }
  788. function zina_sitemap_frequency($interval) {
  789. $frequencies = array(
  790. 'always' => 3600,
  791. 'hourly' => 86400,
  792. 'daily' => 604800,
  793. 'weekly' => 2419200,
  794. 'monthly' => 29030400,
  795. 'yearly' => 100000000,
  796. 'never' => 0,
  797. );
  798. foreach ($frequencies as $frequency => $value)
  799. if ($interval <= $value || $frequency == 'never') break;
  800. return $frequency;
  801. }
  802. function zina_filter_html($text, $tags) {
  803. global $zc;
  804. $allowed_tags = preg_split('/\s+|<|>/', $tags, -1, PREG_SPLIT_NO_EMPTY);
  805. $text = zina_filter_xss($text, $allowed_tags);
  806. return trim($text);
  807. }
  808. function zina_filter_xss($string, $allowed_tags) {
  809. if (!zvalidate_utf8($string)) return '';
  810. // Store the input format
  811. zina_filter_xss_split($allowed_tags, TRUE);
  812. // Remove NUL characters (ignored by some browsers)
  813. $string = str_replace(chr(0), '', $string);
  814. // Remove Netscape 4 JS entities
  815. $string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
  816. // Defuse all HTML entities
  817. $string = str_replace('&', '&amp;', $string);
  818. // Change back only well-formed entities in our whitelist
  819. // Decimal numeric entities
  820. $string = preg_replace('/&amp;#([0-9]+;)/', '&#\1', $string);
  821. // Hexadecimal numeric entities
  822. $string = preg_replace('/&amp;#[Xx]0*((?:[0-9A-Fa-f]{2})+;)/', '&#x\1', $string);
  823. // Named entities
  824. $string = preg_replace('/&amp;([A-Za-z][A-Za-z0-9]*;)/', '&\1', $string);
  825. return preg_replace_callback('%(<(?=[^a-zA-Z!/])|<[^>]*(>|$)|>)%x', 'zina_filter_xss_split', $string);
  826. }
  827. function zina_filter_xss_split($m, $store = false) {
  828. static $allowed_html;
  829. if ($store) {
  830. $allowed_html = array_flip($m);
  831. return;
  832. }
  833. $string = $m[1];
  834. if (substr($string, 0, 1) != '<') {
  835. return '&gt;';
  836. } else if (strlen($string) == 1) {
  837. return '&lt;';
  838. }
  839. if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches)) {
  840. // Seriously malformed
  841. return '';
  842. }
  843. $slash = trim($matches[1]);
  844. $elem = &$matches[2];
  845. $attrlist = &$matches[3];
  846. if (!isset($allowed_html[strtolower($elem)])) return '';
  847. if ($slash != '') return "</$elem>";
  848. // Is there a closing XHTML slash at the end of the attributes?
  849. // In PHP 5.1.0+ we could count the changes, currently we need a separate match
  850. $xhtml_slash = preg_match('%\s?/\s*$%', $attrlist) ? ' /' : '';
  851. $attrlist = preg_replace('%(\s?)/\s*$%', '\1', $attrlist);
  852. // Clean up attributes
  853. $attr2 = implode(' ', zina_filter_xss_attributes($attrlist));
  854. $attr2 = preg_replace('/[<>]/', '', $attr2);
  855. $attr2 = strlen($attr2) ? ' '. $attr2 : '';
  856. return "<$elem$attr2$xhtml_slash>";
  857. }
  858. function zina_filter_xss_attributes($attr) {
  859. $attrarr = array();
  860. $mode = 0;
  861. $attrname = '';
  862. while (strlen($attr) != 0) {
  863. // Was the last operation successful?
  864. $working = 0;
  865. switch ($mode) {
  866. case 0:
  867. // Attribute name, href for instance
  868. if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
  869. $attrname = strtolower($match[1]);
  870. $skip = ($attrname == 'style' || substr($attrname, 0, 2) == 'on');
  871. $working = $mode = 1;
  872. $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
  873. }
  874. break;
  875. case 1:
  876. // Equals sign or valueless ("selected")
  877. if (preg_match('/^\s*=\s*/', $attr)) {
  878. $working = 1; $mode = 2;
  879. $attr = preg_replace('/^\s*=\s*/', '', $attr);
  880. break;
  881. }
  882. if (preg_match('/^\s+/', $attr)) {
  883. $working = 1; $mode = 0;
  884. if (!$skip) {
  885. $attrarr[] = $attrname;
  886. }
  887. $attr = preg_replace('/^\s+/', '', $attr);
  888. }
  889. break;
  890. case 2:
  891. // Attribute value, a URL after href= for instance
  892. if (preg_match('/^"([^"]*)"(\s+|$)/', $attr, $match)) {
  893. $thisval = zina_filter_xss_bad_protocol($match[1]);
  894. if (!$skip) {
  895. $attrarr[] = "$attrname=\"$thisval\"";
  896. }
  897. $working = 1;
  898. $mode = 0;
  899. $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
  900. break;
  901. }
  902. if (preg_match("/^'([^']*)'(\s+|$)/", $attr, $match)) {
  903. $thisval = zina_filter_xss_bad_protocol($match[1]);
  904. if (!$skip) {
  905. $attrarr[] = "$attrname='$thisval'";;
  906. }
  907. $working = 1; $mode = 0;
  908. $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
  909. break;
  910. }
  911. if (preg_match("%^([^\s\"']+)(\s+|$)%", $attr, $match)) {
  912. $thisval = zina_filter_xss_bad_protocol($match[1]);
  913. if (!$skip) {
  914. $attrarr[] = "$attrname=\"$thisval\"";
  915. }
  916. $working = 1; $mode = 0;
  917. $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
  918. }
  919. break;
  920. }
  921. if ($working == 0) {
  922. // not well formed, remove and try again
  923. $attr = preg_replace('/
  924. ^
  925. (
  926. "[^"]*("|$) # - a string that starts with a double quote, up until the next double quote or the end of the string
  927. | # or
  928. \'[^\']*(\'|$)| # - a string that starts with a quote, up until the next quote or the end of the string
  929. | # or
  930. \S # - a non-whitespace character
  931. )* # any number of the above three
  932. \s* # any number of whitespaces
  933. /x', '', $attr);
  934. $mode = 0;
  935. }
  936. }
  937. // the attribute list ends with a valueless attribute like "selected"
  938. if ($mode == 1) {
  939. $attrarr[] = $attrname;
  940. }
  941. return $attrarr;
  942. }
  943. function zina_filter_xss_bad_protocol($string, $decode = TRUE) {
  944. static $allowed_protocols;
  945. if (!isset($allowed_protocols)) {
  946. $allowed_protocols = array_flip(array('http', 'https', 'ftp', 'mailto', '{internal'));
  947. }
  948. // Get the plain text representation of the attribute value (i.e. its meaning).
  949. if ($decode) $string = zdecode_entities($string);
  950. // Iteratively remove any invalid protocol found.
  951. do {
  952. $before = $string;
  953. $colonpos = strpos($string, ':');
  954. if ($colonpos > 0) {
  955. // We found a colon, possibly a protocol. Verify.
  956. $protocol = substr($string, 0, $colonpos);
  957. // If a colon is preceded by a slash, question mark or hash, it cannot
  958. // possibly be part of the URL scheme. This must be a relative URL,
  959. // which inherits the (safe) protocol of the base document.
  960. if (preg_match('![/?#]!', $protocol)) {
  961. break;
  962. }
  963. // Per RFC2616, section 3.2.3 (URI Comparison) scheme comparison must be case-insensitive
  964. // Check if this is a disallowed protocol.
  965. if (!isset($allowed_protocols[strtolower($protocol)])) {
  966. $string = substr($string, $colonpos + 1);
  967. }
  968. }
  969. } while ($before != $string);
  970. return zcheck_plain($string);
  971. }
  972. function zdbg($x, $exit = false, $phpinfo = false) {
  973. echo '<pre>';
  974. print_r($x);
  975. echo '</pre>'."\n";
  976. if ($phpinfo) phpinfo(32);
  977. if ($exit) exit;
  978. }
  979. ?>