Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
general.inc
1 <?php
43 function sq_error_handler($err_no, $err_msg, $err_file, $err_line)
44 {
46  // NOTE: changes to this function should also be considered for the Cron_Job::_errorHandler() //
48 
49  $current_level = error_reporting();
50 
51  // the function was prepended with an '@'
52  if ($current_level === 0) return;
53 
54  // this error level is not set, so dont show the error
55  if (($err_no & $current_level) == 0) return;
56 
57  static $num_errors = 0;
58  $num_errors++;
59 
60  $err_msg = strip_tags($err_msg);
61 
62  $terminate = ((E_USER_ERROR | E_ERROR) & $err_no);
63 
64  // If a PHP 5.2 recoverable error, then also terminate
65  if (defined('E_RECOVERABLE_ERROR') && $err_no == E_RECOVERABLE_ERROR) {
66  $terminate = TRUE;
67  }
68 
69  // Strip out the file path begining
70  $bt = debug_backtrace();
71 
72  if (count($bt) > 1) {
73  $real_bt_index = 0;
74 
75  while (($real_bt_index < count($bt)-1) && (((FALSE !== strpos(array_get_index($bt[$real_bt_index], 'class'), 'Locale_Manager')) || (FALSE !== strpos(array_get_index($bt[$real_bt_index], 'file'), 'locale_manager'))) || ($real_bt_index === 0 && array_get_index($bt[$real_bt_index], 'function', '') == __FUNCTION__) && array_get_index($bt[$real_bt_index], 'function', '') == __FILE__)) {
76  $real_bt_index++;
77  }
78 
79  $err_file = (($err_no === E_STRICT) || ($real_bt_index == 0 && !isset($bt[$real_bt_index]['file']))) ? hide_system_root($bt['0']['args']['2']) : hide_system_root($bt[$real_bt_index]['file']);
80  $err_line = (($err_no === E_STRICT) || ($real_bt_index == 0 && !isset($bt[$real_bt_index]['file']))) ? hide_system_root($bt['0']['args']['3']) : hide_system_root($bt[$real_bt_index]['line']);
81  $err_msg = hide_system_root($err_msg);
82  }
83 
84  // if this is a serious error, do a backtrace
85  $bt_str = '';
86  if ($terminate || (($err_no & ~E_USER_NOTICE) && (SQ_CONF_DEBUG & 2))) {
87  require_once SQ_FUDGE_PATH.'/dev/dev.inc';
88  $bt_str = hide_system_root(array_contents($bt, 3));
89  }
90 
91  $err_name = get_error_name($err_no);
92  $bg_colour = get_error_colour($err_no);
93 
94  // send a report to the system error log
95  if (ini_get('log_errors')) {
96  $text_msg = strip_tags(preg_replace(Array('/<br\\/?>/i', '/<p[^>]*>/i'), Array("\n", "\n\n"), $err_msg));
97  log_error($text_msg, $err_no, $err_file, $err_line);
98  }
99 
100  // OK, because we want our errors to actually be displayed, kill any output buffering
101 
102  $buffers = Array();
103  while (ob_get_level() > SQ_INIT_OB_LEVEL) {
104  $buffers[] = ob_get_contents();
105  ob_end_clean();
106  }
107 
108  if ((boolean)SQ_CONF_ERRORS_LOG_TO_SYSLOG === TRUE) {
109  log_to_syslog($err_no, $err_msg, $err_file, $err_line);
110  }
111 
112  $type = ($GLOBALS['SQ_OUTPUT_TYPE'] == 'html' && SQ_PHP_CLI) ? 'text' : $GLOBALS['SQ_OUTPUT_TYPE'];
113 
114  // if we are in XML output type then, send our error as XML
115  switch ($GLOBALS['SQ_OUTPUT_TYPE']) {
116  case 'xml' :
117  $msg = "$err_msg\nFile: $err_file\nLine:$err_line";
118 
119  $root = simplexml_load_string('<xml></xml>');
120  $output = $root->addChild('error', $msg);
121  header('Content-Type: text/xml');
122  echo $output->asXML();
123  /* XML output
124  <?xml version="1.0"?>
125  <error>Unable to Move Asset, Link #64 not found [AMAP0032]</error>
126  */
127 
128  exit(); // we need to always exit for XML otherwise we are likely to end up with XML parse errors at the other end
129  break;
130 
131  case 'text' :
132  // if they haven't put tags in the err msg assume it to be plain text
133  $err_msg = strip_tags(preg_replace(Array('/<br\\/?>/i', '/<p[^>]*>/i'), Array("\n", "\n\n"), $err_msg));
134  $lines = explode("\n", $err_msg);
135  $len = 7 + strlen($err_file);
136  $len = max($len, 7 + strlen($err_line));
137  foreach ($lines as $line) {
138  $len = max($len, strlen($line));
139  }
140  $len += 2;
141  $str = '+'.str_repeat('-', $len)."+\n".
142  '| '.$err_name.str_repeat(' ', $len - 2 - strlen($err_name))." |\n".
143  '|'.str_repeat('-', $len)."|\n";
144  if (SQ_CONF_DEBUG & 1) {
145  $str .= '| File : '.$err_file.str_repeat(' ', $len - 9 - strlen($err_file))." |\n".
146  '| Line : '.$err_line.str_repeat(' ', $len - 9 - strlen($err_line))." |\n".
147  '|'.str_repeat('-', $len)."|\n";
148  }
149  foreach ($lines as $line) {
150  $str .= '| '.$line.str_repeat(' ', $len - 2 - strlen($line))." |\n";
151  }
152 
153  $str .= '+'.str_repeat('-', $len)."+\n";
154 
155  // if we are from the command line send this to std err
156  if (SQ_PHP_CLI) {
157  fwrite(STDERR, $str);
158  } else {
159  echo $str;
160  }
161 
162  // Uncomment below for debugging from cmdline
163  //error_log($str."\n".$bt_str."\n".str_repeat("=+", 50)."\n", 3, SQ_DATA_PATH.'/private/logs/back_traces.log');
164 
165  break;
166 
167  case 'html' :
168  default :
169 
170  // if we are in the frontend and we're not supposed to see the errors
171  if (hide_frontend_errors() && !(SQ_IN_BACKEND || SQ_IN_LIMBO)) {
172  break;
173  }
174 
175  // if they haven't put tags in the err msg assume it to be plain text
176  if ($err_msg == strip_tags($err_msg)) {
177  $err_msg = nl2br(htmlspecialchars($err_msg));
178  }
179 
180  $error_title = 'background-color: '.$bg_colour.'; font-size: 14px; font-weight: bold; color: #ffffff; font-family: verdana, arial, sans-serif; vertical-align: top;';
181  $error_data = 'background-color: '.$bg_colour.'; font-size: 12px; color: #ffffff; font-family: verdana, arial, sans-serif; vertical-align: top;';
182  if(empty($buffers)) echo '</script></table></table></table></table><br/>';
183  if(!(SQ_IN_BACKEND || SQ_IN_LIMBO)) echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
184  ?>
185  <table bgcolor="#c0c0c0" cellspacing="0" border="1" cellpadding="2" bordercolor="#ff0000">
186  <tr>
187  <td style="<?php echo $error_title; ?>">
188  <?php echo $err_name; ?>
189  </td>
190  </tr>
191  <tr>
192  <td style="<?php echo $error_data; ?>">
193  <?php
194  if (SQ_CONF_DEBUG & (1 | 2)) {
195  ?>
196  <table bgcolor="#dddddd" cellpadding="2" cellspacing="0" border="0">
197  <?php
198  if (SQ_CONF_DEBUG & 1) {
199  ?>
200  <tr>
201  <td style="<?php echo $error_title; ?>" align="right">File:</td>
202  <td style="<?php echo $error_data; ?>"><?php echo $err_file; ?></td>
203  <td style="<?php echo $error_title; ?>" align="right">Line:</td>
204  <td style="<?php echo $error_data; ?>"><?php echo $err_line; ?></td>
205  </tr>
206  <?php
207  }//end if (DEBUG & File+Line)
208  ?>
209  <tr>
210  <td style="<?php echo $error_title; ?>" align="right">Message:</td>
211  <td style="<?php echo $error_data; ?>" colspan="3"><?php echo $err_msg; ?></td>
212  </tr>
213  <?php
214  // if there is a backtrace string create a simple bit of JS to allow it to be popped up into a new window
215  if ((SQ_CONF_DEBUG & 2) && $bt_str) {
216  ?>
217  <tr>
218  <td style="<?php echo $error_title; ?>" align="right">Backtrace:</td>
219  <td style="<?php echo $error_data; ?>" colspan="3">
220  <script language="JavaScript" type="text/javascript">
221  <!--
222  function print_backtrace_<?php echo $num_errors; ?>() {
223  var alert_win = window.open('', 'backtrace_window_<?php echo $num_errors; ?>', 'resizable=yes,scrollbars=yes,width=800,height=500');
224  alert_win.document.open();
225  alert_win.document.writeln("<html><head><title>MySource Backtrace</title></head><body><pre>");
226  alert_win.document.writeln("<?php echo str_replace("\n", '\\n', addslashes(htmlspecialchars($bt_str))); ?>");
227  alert_win.document.writeln("</pre></body></html>");
228  alert_win.document.close();
229  alert_win.focus();
230  }
231 
232  // -->
233  </script>
234  <a href="javascript: print_backtrace_<?php echo $num_errors; ?>();" style="color: #ffffff;">Show</a>
235  </td>
236  </tr>
237  <?php
238  }//end if (DEBUG & Backtrace)
239  ?>
240  </table>
241  <?php
242  } else {
243  echo $err_msg;
244 
245  }//end if (SQ_CONF_DEBUG & (File+Line | Backtrace)
246  ?>
247  </td>
248  </tr>
249  </table><br/>
250  <?php
251 
252  }//end switch ($GLOBALS['SQ_OUTPUT_TYPE'])
253 
254  // now just restore any buffered output here - it's as though nothing ever happened :)
255  for ($i = count($buffers) - 1; $i >= 0; $i--) {
256  ob_start();
257  echo $buffers[$i];
258  }
259 
260  // mail the tech email if there was a fatal error
261  if ($terminate) {
262 
263  // if they haven't put tags in the err msg assume it to be plain text
264  $err_msg = strip_tags(preg_replace(Array('/<br\\/?>/i', '/<p[^>]*>/i'), Array("\n", "\n\n"), $err_msg));
265  $db_type = 'N/A';
266  $db = MatrixDAL::getDb();
267  if (!is_null($db)) $db_type = MatrixDAL::getDbType();
268 
269  $matrix_version = 'N/A';
270  if (defined('SQ_SYSTEM_VERSION')) {
271  $matrix_version = SQ_SYSTEM_VERSION;
272  }
273 
274  $str = '*'.$err_name."*\n".
275  'File : '.$err_file."\n".
276  'Line : '.$err_line."\n".
277  'Version : '.$matrix_version."\n".
278  'DB Type : '.$db_type."\n".
279  "\n".
280  $err_msg."\n".
281  "------------------------------------------------------------------\n".
282  "*User Details*\n";
283  if (!empty($GLOBALS['SQ_SYSTEM']) && is_object($GLOBALS['SQ_SYSTEM']->user)) {
284  $str .= 'User: "'.$GLOBALS['SQ_SYSTEM']->user->name.'" (#'.$GLOBALS['SQ_SYSTEM']->user->id.")\n";
285  }
286  $str .= (!empty($_SERVER['REMOTE_ADDR']) ? 'IP Address: '.$_SERVER['REMOTE_ADDR']."\n" : '');
287  $str .= (!empty($_SERVER['HTTP_USER_AGENT']) ? 'User-Agent: '.$_SERVER['HTTP_USER_AGENT']."\n" : '');
288 
289  $str .= "------------------------------------------------------------------\n".
290  "*Root Urls*\n".
291  SQ_CONF_SYSTEM_ROOT_URLS."\n".
292  "------------------------------------------------------------------\n";
293  if (SQ_PHP_CLI) {
294  $str .= "*Command and Arguments*\n".
295  implode(' ', $_SERVER['argv'])."\n";
296  } else {
297  $str .= "*Current URL*\n".
298  current_protocol().'://'.array_get_index($_SERVER, 'HTTP_HOST', 'NO HOST').array_get_index($_SERVER, 'REQUEST_URI', '/NO REQUEST URI')."\n";
299  }
300 
301 
302  $str .= "------------------------------------------------------------------\n".
303  "*Back Trace*\n".
304  $bt_str."\n";
305 
306  // ensure we have a valid email address to send error notifications to
307  // fail silently if none present
308  if (SQ_CONF_TECH_EMAIL) {
309  mail(SQ_CONF_TECH_EMAIL, '['.$err_name.'] '.SQ_CONF_SYSTEM_NAME, $str, 'From: '.SQ_CONF_TECH_EMAIL."\r\n");
310  }
311 
312  exit(1);
313 
314  }//end if ($terminate)
315 
316 }//end sq_error_handler()
317 
318 
327 function sq_exception_handler($e)
328 {
329  $nl = SQ_PHP_CLI ? "\n" : "<br />";
330 
331  // Sanatise the exception message
332  $msg = SQ_PHP_CLI ? $e->getMessage() : htmlspecialchars($e->getMessage(), ENT_QUOTES);
333  $fileline = "' in ".$e->getFile()."(".$e->getLine()."): ";
334  $trace = $e->getTrace();
335  // Build the backtrace
336  $backtrace = '';
337  foreach($trace as $key => $val) {
338  $file = $val['file'];
339  $func_name = $val['function'];
340  $line = $val['line'];
341  $args_str = '';
342  foreach($val['args'] as $arg) {
343  if (is_array($arg)) {
344  $args_str .= "Array, ";
345  } else if (is_object($arg)) {
346  $args_str .= "Object(".get_class($arg)."), ";
347  } else if (is_bool($arg)) {
348  $args_str .= ($arg === TRUE ? "true" : "false").", ";
349  } else if ($arg === null) {
350  $args_str .= "null, ";
351  } else {
352  // Treat rest of the types as a string
353  if (strlen($arg > 20)) {
354  $arg = substr($arg,0, 20)."...";
355  }
356  $arg = str_replace("'", "\'", $arg);
357  if (!SQ_PHP_CLI) {
358  // Sanatise the arguments
359  $arg = htmlspecialchars($arg, ENT_QUOTES);
360  }
361  $args_str .= "'".$arg."', ";
362  }
363  }//end foreach
364  $args_str = rtrim($args_str, ', ' );
365 
366  if ($key == 0) {
367  $backtrace .= $func_name."(".$args_str.")".$nl;
368  } else {
369  $backtrace .= "#".$key." ".$file."(".$line."): ".$func_name."(".$args_str.")".$nl;
370  }
371  }//end foreach
372 
373  $err_msg = "Fatal error: Uncaught exception '".get_class($e)."' with message: '".$msg;
374  // Should the exeception error be shown?
375  if (SQ_PHP_CLI || SQ_IN_BACKEND || SQ_IN_LIMBO || !hide_frontend_errors()) {
376  $display_msg = $err_msg;
377  if (SQ_CONF_DEBUG & 1) {
378  $display_msg .= $fileline;
379  }
380  if (SQ_CONF_DEBUG & 2) {
381  $display_msg .= $backtrace;
382  }
383  echo $display_msg;
384  }
385 
386  // Send a report to the system error log
387  if (ini_get('log_errors')) {
388  $log_msg = str_replace('<br />', "\n", htmlspecialchars_decode($err_msg.$fileline.$backtrace));
389  log_error($log_msg, E_ERROR);
390  }
391 
392  exit(1);
393 
394 }//end sq_exception_handler()
395 
396 
403 function hide_frontend_errors()
404 {
405  $query = array_get_index($_SERVER, 'QUERY_STRING', '');
406 
407  // Config hard set
408  if (SQ_CONF_ERRORS_HIDE_FRONTEND) {
409  // Also check for an override by a query string var and a valid user
410  if (isset($GLOBALS['SQ_SYSTEM']->user)) {
411  $user = $GLOBALS['SQ_SYSTEM']->user;
412  } else {
413  $user = NULL;
414  }//end if
415 
416  // Check for at least system administrator access
417  if ((preg_match('/SQ_SHOW_ERRORS=1/', $query) != 0) && (!is_null($user) && $user instanceof System_User)) {
418  return FALSE;
419  } else {
420  return TRUE;
421  }//end if
422  } else {
423  return FALSE;
424  }//end if
425 
426 }//end hide_front_errors
427 
428 
433 function log_to_syslog($error_code, $message, $file, $line)
434 {
435  $syslog_code = LOG_NOTICE;
436 
437  switch ($error_code) {
438  case E_ERROR:
439  case E_USER_ERROR:
440  $syslog_code = LOG_ERR;
441  break;
442 
443  case E_WARNING:
444  case E_USER_WARNING:
445  $syslog_code = LOG_WARNING;
446  break;
447 
448  default:
449  $syslog_code = LOG_NOTICE;
450  break;
451 
452  }//end switch
453 
454  if ((SQ_CONF_DEBUG & 1) !== 0) {
455  $message .= ' ('.$file.':'.$line.')';
456  }
457 
458  syslog($syslog_code, $message);
459 
460 }//end log_to_syslog()
461 
462 
471 function get_error_name($error_code)
472 {
473  $name = '';
474 
475  if (empty($error_code)) return $name;
476 
477  // Extra codes depending
478  if (defined('E_RECOVERABLE_ERROR') && $error_code == E_RECOVERABLE_ERROR) {
479  // PHP 5.2 introduces a "recoverable error" code (4096).
480  // As Matrix uses a PHP 5.1 baseline, it's worth handling recoverable
481  // errors the same way as normal E_ERROR
482  $name = 'PHP Error';
483  } else if (defined('E_STRICT') && $error_code == E_STRICT) {
484  // If we are using PHP5, E_STRICT will be defined (2048).
485  $name = 'PHP 5 Strict Standards';
486  } else {
487  switch ($error_code) {
488  case E_USER_ERROR :
489  $name = SQ_SYSTEM_SHORT_NAME.' Error';
490  break;
491  case E_USER_WARNING :
492  $name = SQ_SYSTEM_SHORT_NAME.' Warning';
493  break;
494  case E_USER_NOTICE :
495  $name = SQ_SYSTEM_SHORT_NAME.' Notice';
496  break;
497  case E_ERROR :
498  $name = 'PHP Error';
499  break;
500  case E_WARNING :
501  $name = 'PHP Warning';
502  break;
503  case E_NOTICE :
504  $name = 'PHP Notice';
505  break;
506  default :
507  $name = 'Unknown Error Type - '.$error_code;
508  }
509  }
510 
511  return $name;
512 
513 }//end get_error_name()
514 
515 
524 function get_error_colour($error_code)
525 {
526  $colour = '';
527 
528  if (defined('E_RECOVERABLE_ERROR') && $error_code == E_RECOVERABLE_ERROR) {
529  // PHP 5.2 "recoverable error" code (4096) - considered an normal PHP
530  // Error by Matrix to be consistent with PHP 5.1
531  $colour = '#0066CC';
532  } else if (defined('E_STRICT') && $error_code == E_STRICT) {
533  // If we are using PHP5, E_STRICT will be defined (2048).
534  $colour = '#594165';
535  } else {
536  switch ($error_code) {
537  case E_USER_ERROR :
538  $colour = '#993333';
539  break;
540  case E_USER_WARNING :
541  $colour = '#DBA53B';
542  break;
543  case E_USER_NOTICE :
544  $colour = '#17AA92';
545  break;
546  case E_ERROR :
547  $colour = '#0066CC';
548  break;
549  case E_WARNING :
550  $colour = '#0066CC';
551  break;
552  case E_NOTICE :
553  $colour = '#0066CC';
554  break;
555  default :
556  $colour = '#FF0000';
557  break;
558  }//end switch
559  }
560 
561  return $colour;
562 
563 }//end get_error_colour()
564 
565 
574 function sq_web_path($path='base')
575 {
576  static $paths = Array();
577 
578  if (isset($paths[$path])) return $paths[$path];
579 
580  switch ($path) {
581  case 'base' :
582  // preg bit is a check for the people who are using symlinked versions
583  $paths[$path] = (SQ_IN_BACKEND) ? '..' : ((preg_match('/index.php$/', current_url())) ? './index.php' : '.');
584  break;
585 
586  case 'admin' :
587  // preg bit is a check for the people who are using symlinked versions
588  $paths[$path] = (SQ_IN_BACKEND) ? '.' : ((preg_match('/index.php$/', current_url())) ? './index.php' : '.').'/'.SQ_CONF_BACKEND_SUFFIX;
589  break;
590 
591  case 'edit' :
592  // preg bit is a check for the people who are using symlinked versions
593  $paths[$path] = (SQ_IN_LIMBO) ? '.' : ((preg_match('/index.php$/', current_url())) ? './index.php' : '.').'/'.SQ_CONF_LIMBO_SUFFIX;
594  break;
595 
596  case 'login' :
597  // preg bit is a check for the people who are using symlinked versions
598  $paths[$path] = (SQ_IN_LOGIN) ? '.' : ((preg_match('/index.php$/', current_url())) ? './index.php' : '.').'/'.SQ_CONF_LOGIN_SUFFIX;
599  break;
600 
601  case 'root_url' :
602  $root_urls = explode("\n", SQ_CONF_SYSTEM_ROOT_URLS);
603  $current_url = strip_url(current_url(FALSE, TRUE));
604  // if we are in the backend strip the suffix
605  if (SQ_IN_BACKEND) {
606  $current_url = preg_replace('/\\/'.SQ_CONF_BACKEND_SUFFIX.'$/', '', $current_url);
607  }
608  $tmp = $root_urls[0];
609  for ($i = 1; $i < count($root_urls); $i++) {
610  if (substr($current_url, 0, strlen($root_urls[$i])) == $root_urls[$i]) {
611  // if the current tmp has the same start
612  if (substr($tmp, 0, strlen($root_urls[$i])) == $root_urls[$i]) {
613  // then we only use it if it's a longer (and therefore closer) string
614  if (strlen($tmp) < strlen($root_urls[$i])) {
615  $tmp = $root_urls[$i];
616  }
617  } else {
618  $tmp = $root_urls[$i];
619  }
620  }
621  }
622  // if we are in the symlink system remove the URL
623  $paths[$path] = current_protocol().'://'.preg_replace('/\/index.php$/', '', $tmp);
624  break;
625 
626  case 'lib' :
627  $paths[$path] = sq_web_path('root_url').'/__lib';
628  break;
629 
630  case 'data' :
631  if (SQ_CONF_STATIC_ROOT_URL == '') {
632  $paths[$path] = sq_web_path('root_url').'/__data';
633  } else {
634  // use the most appropriate protocol
635  switch (current_protocol()) {
636  case 'http' :
637  $protocol = (SQ_CONF_STATIC_ROOT_HTTP) ? 'http' : 'https';
638  break;
639  case 'https' :
640  $protocol = (SQ_CONF_STATIC_ROOT_HTTPS) ? 'https' : 'http';
641  break;
642  }
643  $paths[$path] = $protocol.'://'.SQ_CONF_STATIC_ROOT_URL;
644  }
645  break;
646 
647  case 'fudge' :
648  $paths[$path] = sq_web_path('root_url').'/__fudge';
649  break;
650 
651  }//end switch ($path)
652 
653  return $paths[$path];
654 
655 }//end sq_web_path()
656 
657 
667 function sq_root_url($url, $inc_protocol=TRUE)
668 {
669  // see sq_web_path('root_url') for more info
670  $protocol = ($inc_protocol) ? array_get_index(parse_url($url), 'scheme', 'http').'://' : '';
671  // strip the protocol, only append it if inc_protocol is true
672  $current_url = strip_url($url, TRUE);
673  $root_urls = explode("\n", SQ_CONF_SYSTEM_ROOT_URLS);
674 
675  // if we are in the backend strip the suffix
676  if (SQ_IN_BACKEND) {
677  $current_url = preg_replace('/\\/'.SQ_CONF_BACKEND_SUFFIX.'$/', '', $current_url);
678  }
679  $tmp = $root_urls[0];
680  for ($i = 1; $i < count($root_urls); $i++) {
681  if (substr($current_url, 0, strlen($root_urls[$i])) == $root_urls[$i]) {
682  // if the current tmp has the same start
683  if (substr($tmp, 0, strlen($root_urls[$i])) == $root_urls[$i]) {
684  // then we only use it if it's a longer (and therefore closer) string
685  if (strlen($tmp) < strlen($root_urls[$i])) {
686  $tmp = $root_urls[$i];
687  }
688  } else {
689  $tmp = $root_urls[$i];
690  }
691  }
692  }
693 
694  return strip_url($protocol.preg_replace('/\/index.php$/', '', $tmp));
695 
696 }//end sq_root_url()
697 
698 
707 function get_asset_hash($assetid)
708 {
709  $assetid = trim($assetid);
710  do {
711  $hash = 0;
712  $len = strlen($assetid);
713  for ($i = 0; $i < $len; $i++) {
714  if ((int) $assetid{$i} != $assetid{$i}) {
715  $hash += ord($assetid{$i});
716  } else {
717  $hash += (int) $assetid{$i};
718  }
719  }
720  $assetid = (string) $hash;
721  } while ($hash > SQ_CONF_NUM_DATA_DIRS);
722 
723  while (strlen($hash) != 4) {
724  $hash = '0'.$hash;
725  }
726  return $hash;
727 
728 }//end get_asset_hash()
729 
730 
740 function asset_data_path_suffix($type_code, $assetid)
741 {
742  return 'assets/'.$type_code.'/'.get_asset_hash($assetid).'/'.$assetid;
743 
744 }//end asset_data_path_suffix()
745 
746 
756 function current_url($inc_protocol=TRUE, $strip_backend_suffix=FALSE)
757 {
758  if (SQ_PHP_CLI && !isset($_SERVER['HTTP_HOST'])) {
759  // being called from eg. a squiz server HIPO
760  $url = '';
761  } else {
762  $host = array_get_index($_SERVER, 'HTTP_HOST', FALSE);
763  if (!$host) {
764  // try to get the host name from the HTTP_HOST server variable just in case
765  // if previous test failed, this one will probably not help, but before dying we try anyway
766  $host = array_get_index($_SERVER, 'SERVER_NAME', FALSE);
767  if (!$host) {
768  trigger_localised_error('SYS0107', E_USER_ERROR);
769  }
770  }
771  $url = (($inc_protocol) ? current_protocol().'://' : '').$host.$_SERVER['PHP_SELF'];
772 
773  // if we are in the backend remove the suffix
774  if ($strip_backend_suffix && (SQ_IN_BACKEND || SQ_IN_LIMBO || SQ_IN_LOGIN)) {
775  $url = preg_replace('/'.SQ_CONF_BACKEND_SUFFIX.'\/?$/', '', $url);
776  $url = preg_replace('/'.SQ_CONF_LIMBO_SUFFIX.'\/?$/', '', $url);
777  $url = preg_replace('/'.SQ_CONF_LOGIN_SUFFIX.'\/?$/', '', $url);
778  }
779  $url = preg_replace('/'.SQ_CONF_NOCACHE_SUFFIX.'\/?$/', '', $url);
780  $url = preg_replace('/\/'.SQ_CONF_RECACHE_SUFFIX.'\/?$/', '', $url);
781  $url = preg_replace('/\/'.SQ_CONF_PERFORMANCE_SUFFIX.'\/?$/', '', $url);
782  $url = preg_replace('/\/'.SQ_CONF_PERFORMANCE_TIMING_SUFFIX.'\/?$/', '', $url);
783  $url = preg_replace('/\/'.SQ_CONF_PERFORMANCE_RESULT_SUFFIX.'\/?$/', '', $url);
784  }
785 
786  if (empty($url)) { // url empty, just use the first system root url
787  if (!defined('SQ_CONF_SYSTEM_ROOT_URLS')) {
788  include_once SQ_DATA_PATH.'/private/conf/main.inc';
789  }
790  $root_urls = explode("\n", SQ_CONF_SYSTEM_ROOT_URLS);
791  // trim in case there's a /r in there
792  $url = (($inc_protocol) ? current_protocol().'://' : '').trim($root_urls[0]).'/';
793  }
794 
795  return $url;
796 
797 }//end current_url()
798 
799 
808 function clean_url($url)
809 {
810  $bits = Array(
811  '__data',
812  '__lib',
813  '__fudge',
814  SQ_CONF_LOGIN_SUFFIX,
815  SQ_CONF_LIMBO_SUFFIX,
816  SQ_CONF_BACKEND_SUFFIX,
817  SQ_CONF_NOCACHE_SUFFIX,
818  SQ_CONF_RECACHE_SUFFIX,
819  SQ_CONF_PERFORMANCE_SUFFIX,
820  );
821 
822  foreach ($bits as $bit) {
823  $url = preg_replace('/\/'.$bit.'.*/', '/', $url);
824  }
825  return $url;
826 
827 }//end clean_url()
828 
829 
836 function current_protocol()
837 {
838  if (is_ssl_accelerated()) return 'https';
839  return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
840 
841 }//end current_protocol()
842 
843 
851 function is_ssl_accelerated()
852 {
853  if (SQ_PHP_CLI) return FALSE;
854 
855  $enabled = FALSE;
856  if (SQ_SSLA_ENABLED) {
857  $enabled = TRUE;
858 
859  $match_method = SQ_SSLA_MATCH;
860  if ($match_method !== 'header') {
861  $host = array_get_index($_SERVER, 'REMOTE_ADDR');
862  // If the host is not there, we'd be in CLI mode, so no acceleration
863  if ($host === NULL) $enabled = FALSE;
864  if (trim($host) !== trim(SQ_SSLA_IP)) {
865  $enabled = FALSE;
866  }
867  }
868 
869  if ($match_method !== 'ip') {
870  if (isset($_SERVER[SQ_SSLA_HEADER_NAME])) {
871  $header_value = $_SERVER[SQ_SSLA_HEADER_NAME];
872  if (trim($header_value) !== trim(SQ_SSLA_HEADER_VALUE)) {
873  $enabled = FALSE;
874  }
875  } else {
876  $enabled = FALSE;
877  }
878  }
879 
880  }
881 
882  return $enabled;
883 
884 }//end is_ssl_accelerated()
885 
886 
896 function strip_url($url, $strip_protocol=FALSE)
897 {
898  preg_match('|^([a-z]+://)?(.*)$|', $url, $matches);
899  return (($strip_protocol) ? '' : $matches[1]).preg_replace(Array('|/+$|', '|//+|'), Array('', '/'), $matches[2]);
900 
901 }//end strip_url()
902 
903 
914 function get_url_lineage($url, $db_quote = TRUE)
915 {
916  $urls = Array();
917  $pos = strpos($url, "/");
918  while ($pos) {
919  if ($db_quote){
920  $urls[] = MatrixDAL::quote(substr($url, 0, $pos));
921  } else {
922  $urls[] = substr($url, 0, $pos);
923  }
924  $pos = strpos($url, "/", $pos + 1);
925  }
926 
927  return $urls;
928 
929 }//end get_url_lineage()
930 
931 
948 function replace_query_string_vars($replacements, $base_url=NULL, $query_string=NULL, $remove_sq_vars=FALSE)
949 {
950  if (is_null($base_url)) $base_url = current_url();
951  if (is_null($query_string)) {
952  $query_string = array_get_index($_SERVER, 'QUERY_STRING', '');
953  }
954 
955  $replaced_vars = array_keys($replacements);
956  $new_query_string = '';
957 
958  // first replace any existing query string vars and remove any that are NULL
959  $matches = Array();
960  preg_match_all('|&([^=]+)=([^&]+)?|', '&'.$query_string, $matches);
961  foreach ($matches[1] as $num => $var) {
962  if ($remove_sq_vars && (strlen($var) > 3) && (substr(strtoupper($var), 0, 3) == 'SQ_')) continue;
963 
964  if (!in_array($var, $replaced_vars)) {
965  // there is no replacement required
966  $new_query_string .= '&'.$var.'='.$matches[2][$num];
967  } else {
968  $new_value = $replacements[$var];
969  if (!is_null($new_value)) {
970  $new_query_string .= '&'.$var.'='.$new_value;
971  }
972  }
973  }
974 
975  // now add in any new query string vars
976  foreach ($replacements as $var => $value) {
977  if (in_array($var, $matches[1])) continue;
978  if (is_null($value)) continue;
979  $new_query_string .= '&'.$var.'='.$value;
980  }
981  $new_query_string = trim($new_query_string, '&');
982 
983  return $base_url.'?'.$new_query_string;
984 
985 }//end replace_query_string_vars()
986 
987 
999 function bit_elements($num)
1000 {
1001  $num = (int) $num; // make sure it's an int
1002  $count = 1;
1003  $elems = Array();
1004  while ($num > 0) {
1005  // if the first bit is set then this number is one of the elements
1006  if ($num & 1) {
1007  $elems[] = $count;
1008  }
1009  $count *= 2;
1010  // we just keep shifting right until there aren't anymore numbers
1011  $num = $num >> 1;
1012  }
1013 
1014  return $elems;
1015 
1016 }//end bit_elements()
1017 
1018 
1032 function iso8601_ts($iso8601)
1033 {
1034  // we have everything including the time
1035  // No date and time
1036  // As per Bug #2958, PHP 5 interprets '---------- --:--:--' as 30th Nov 1999
1037  // and not returning -1 as an invalid date, so we emulate it here.
1038  if ($iso8601 == '---------- --:--:--') {
1039  return -1;
1040  } else if (preg_match("/^[0-9\-]{4}-[0-9\-]{2}-[0-9\-]{2}$/", $iso8601)) {
1041  // valid but we only have the date
1042  return mktime(
1043  0, 0, 0,
1044  (int) substr($iso8601,5,2),
1045  (int) substr($iso8601,8,2),
1046  (int) substr($iso8601,0,4)
1047  );
1048 
1049  } else if (preg_match('/^[0-9\-]{4}(-[0-9\-]{2}(-[0-9\-]{2}([T| ]{1}[0-9\-]{2}:[0-9\-]{2}(:[0-9\-]{2}(\.[0-9\-]{1,2}){0,1}){0,1}(([\+|-]{1}[0-9\-]{2}:[0-9\-]{2})|Z){0,1}){0,1}){0,1}){0,1}$/', $iso8601)) {
1050  // time zone designator can be Z, +hh:mm or -hh:mm
1051  return mktime(
1052  (int) substr($iso8601,11,2),
1053  (int) substr($iso8601,14,2),
1054  (int) substr($iso8601,17,2),
1055  (int) substr($iso8601,5,2),
1056  (int) substr($iso8601,8,2),
1057  (int) substr($iso8601,0,4)
1058  );
1059 
1060  } else {
1061  return 0;
1062  }
1063 
1064 }//end iso8601_ts()
1065 
1066 
1077 function ts_iso8601($timestamp)
1078 {
1079  return date('Y-m-d H:i:s', $timestamp);
1080 
1081 }//end ts_iso8601()
1082 
1083 
1093 function format_date($timestamp, $format_name)
1094 {
1095  if ($format_name === 'relative') {
1096  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
1097  return easy_short_relative_datetime($timestamp, FALSE);
1098  } else if ($format_name === 'relative-dow') {
1099  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
1100  return easy_short_relative_datetime($timestamp, TRUE);
1101  } else {
1102  $date_formats = get_date_formats();
1103  if (isset($date_formats[$format_name])) {
1104  return date($date_formats[$format_name], $timestamp);
1105  }
1106  }
1107  return '';
1108 
1109 }//end format_date()
1110 
1111 
1122 function get_date_formats()
1123 {
1124  $date_formats = Array(
1125  'short' => 'Y-m-d',
1126  'readable' => 'd M Y g:ia',
1127  'readabledate' => 'd M Y',
1128  'readabletime' => 'g:ia',
1129  'iso8601' => 'Y-m-d\TH:i:s',
1130  'rfc2822' => 'r',
1131  'rfc2822-dateonly' => 'D, d M Y',
1132  'ical' => 'Ymd\THis',
1133  'relative' => NULL,
1134  'relative-dow' => NULL,
1135  );
1136  return $date_formats;
1137 
1138 }//end get_date_formats()
1139 
1140 
1147 function get_date_format_names()
1148 {
1149  $date_formats = get_date_formats();
1150  foreach ($date_formats as $date_id => $date_format) {
1151  $date_formats[$date_id] = translate('date_format_'.$date_id);
1152  }
1153 
1154  return $date_formats;
1155 
1156 }//end get_date_format_names()
1157 
1158 
1172 function array_get_index($array, $index, $default=NULL)
1173 {
1174  if (!is_array($array)) return $default;
1175  if (isset($array[$index])) return $array[$index];
1176  return $default;
1177 
1178 }//end array_get_index()
1179 
1180 
1181 //-- INTERFACES (IMPLENTATION) FNS --//
1182 
1183 
1195 function register_implementation($class, $interface)
1196 {
1197  if (!isset($GLOBALS['SQ_IMPLEMENTATION'])) {
1198  $GLOBALS['SQ_IMPLEMENTATION'] = Array();
1199  }
1200  $GLOBALS['SQ_IMPLEMENTATION'][$class] = (is_array($interface)) ? $interface : Array($interface);
1201 
1202 }//end register_implementation()
1203 
1204 
1214 function implements_interface($class, $interface)
1215 {
1216  if (is_object($class)) {
1217  return ($class instanceof $interface);
1218  } else if (!class_exists($class)) {
1219  trigger_localised_error('SYS0237', E_USER_ERROR, $class);
1220  }
1221 
1222  // Must have been passed a string
1223  $dummy = new $class();
1224  $ret_val = ($dummy instanceof $interface);
1225  unset($dummy);
1226  return $ret_val;
1227 
1228 }//end implements_interface()
1229 
1230 
1245 function log_write($data, $logname=SQ_CONF_LOG_FILE_SYSTEM, $level=E_USER_NOTICE, $encode=TRUE)
1246 {
1247  if (empty($logname) || empty($level)) {
1248  trigger_localised_error('SYS0099', E_USER_ERROR);
1249  return FALSE;
1250  }
1251 
1252  // grab metadata
1253  $current_user = $GLOBALS['SQ_SYSTEM']->user;
1254  $userid = 0;
1255  $username = '';
1256 
1257  if (is_null($current_user)) {
1258  $username = SQ_SYSTEM_SHORT_NAME.' System';
1259  } else {
1260  $userid = $current_user->id;
1261  $username = $current_user->name;
1262  }
1263 
1264  $chars_to_escape = Array('[',']',':',"\n","\r");
1265  $replacements = Array('&#91;','&#93;','&#58;','&#10;','&#13;');
1266 
1267  $username = str_replace($chars_to_escape, $replacements, $username);
1268  $level_name = strtolower(get_error_name($level));
1269 
1270  // mark the data as 'R' (raw), 'S' (serialised) or ' ' (unserialised)
1271  if (is_string($data)) {
1272  $flag = ' ';
1273  } else {
1274  $data = serialize($data);
1275  $flag = 'S';
1276  }
1277 
1278  if ($encode) {
1279  $data = str_replace(Array("\n", "\r"), Array('&#10;', '&#13;'), $data);
1280  } else {
1281  // NOTE: if data is serialised, but requested to be logged raw, we simply mark it as raw
1282  // it will not be unserializable
1283  $flag = 'R';
1284  }
1285 
1286  $date = date('Y-m-d H:i:s');
1287  $log_entry = "[$date][$userid:$username][$level:$level_name][$flag] $data\n";
1288 
1289  if (!$log_entry) return FALSE;
1290 
1291  $logfile = SQ_LOG_PATH.'/'.$logname.SQ_CONF_LOG_EXTENSION;
1292  // check if filename is valid
1293 
1294  // set the UMASK to u=rw,g=rw,o=r (0002), so that the user can write the logfiles
1295  // needed so that step_03 can be run
1296  if (substr(PHP_OS, 0, 3) != 'WIN') {
1297  $old_umask = umask(0113);
1298  }
1299 
1300  $handle = fopen($logfile, 'a');
1301  if (!fwrite($handle, $log_entry)) {
1302  trigger_localised_error('SYS0051', E_USER_WARNING, $logfile);
1303  return FALSE;
1304  }
1305  fclose($handle);
1306 
1307  // Restore the old umask
1308  if (isset($old_umask)) umask($old_umask);
1309 
1310  return TRUE;
1311 
1312 }//end log_write()
1313 
1314 
1329 function log_error($message, $level=E_USER_NOTICE, $file='', $line='', $log_name=SQ_CONF_LOG_FILE_ERROR)
1330 {
1331  if (!is_string($message)) {
1332  trigger_localised_error('SYS0191', E_USER_WARNING);
1333  return FALSE;
1334  }
1335 
1336  if (!is_null($file)) {
1337  $message = "($file:$line) - $message";
1338  }
1339 
1340  // strip out all references to the string identifying the root
1341  $message = str_replace('[SYSTEM_ROOT]', '', $message);
1342 
1343  return log_write($message, $log_name, $level, FALSE);
1344 
1345 }//end log_error()
1346 
1347 
1356 function hide_system_root($message='')
1357 {
1358 
1359  if (SQ_SYSTEM_ROOT !== '.') {
1360  $message = str_replace(Array("\r", SQ_SYSTEM_ROOT), Array('', '[SYSTEM_ROOT]'), $message);
1361  }
1362 
1363  return $message;
1364 
1365 }//end hide_system_root()
1366 
1367 
1377 function translate($string)
1378 {
1379  $args = array_slice(func_get_args(),1);
1380  if (!isset($GLOBALS['SQ_SYSTEM'])) return FALSE;
1381  return $GLOBALS['SQ_SYSTEM']->lm->getString($string, $args);
1382 
1383 }//end translate()
1384 
1385 
1395 function translate_error($code)
1396 {
1397  $args = array_slice(func_get_args(),1);
1398  if (!isset($GLOBALS['SQ_SYSTEM'])) return FALSE;
1399  return $GLOBALS['SQ_SYSTEM']->lm->getErrorMessage($code, $args);
1400 
1401 }//end translate_error()
1402 
1403 
1414 function trigger_localised_error($code, $error_level)
1415 {
1416  $args = array_slice(func_get_args(),2);
1417  if (!isset($GLOBALS['SQ_SYSTEM']) || !is_object($GLOBALS['SQ_SYSTEM']->lm)) {
1418  trigger_error('Error occurred ['.$code.']'."\n".print_r($args, TRUE), $error_level);
1419  return FALSE;
1420  }
1421  return $GLOBALS['SQ_SYSTEM']->lm->raiseError($code, $error_level, $args);
1422 
1423 }//end trigger_localised_error()
1424 
1425 
1442 function sq_print_icon($path, $width, $height, $alt='', $title=NULL, $extras='')
1443 {
1444  echo sq_get_icon($path, $width, $height, $alt, $title, $extras);
1445 
1446 }//end sq_print_icon()
1447 
1448 
1465 function sq_get_icon($path, $width, $height, $alt='', $title=NULL, $extras='')
1466 {
1467  if (is_null($title) && !empty($alt)) {
1468  $title = $alt;
1469  }
1470  if (is_null($title)) $title = '';
1471  if (FALSE !== strpos($extras, 'class=')) {
1472  $extras = preg_replace('/class="([^"]*)"/', 'class="\\1 sq-icon"', $extras);
1473  } else {
1474  $extras .= ' class="sq-icon"';
1475  }
1476  return '
1477  <img src="'.$path.'"
1478  alt="'.$alt.'"
1479  title="'.$title.'"
1480  height="'.$height.'"
1481  width="'.$width.'"
1482  '.$extras.' />
1483  ';
1484 
1485 }//end sq_get_icon()
1486 
1487 
1501 function get_asset_tag_line($assetid, $screen='')
1502 {
1503  // If it's a shadow asset, there is nothing in the database so we cannot use
1504  // the shortcut - we have to get the info from the asset instead
1505  if (strpos($assetid, ':') !== FALSE) {
1506  list($real_assetid, $shadowid) = explode(':', $assetid, 2);
1507  $asset_info = Array();
1508  $shadow_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
1509  if ($shadow_asset) {
1510  $asset_info['type_code'] = $shadow_asset->type();
1511  $asset_info['name'] = $shadow_asset->name;
1512  $asset_info['short_name'] = $shadow_asset->short_name;
1513  $asset_info['status'] = $shadow_asset->status;
1514  $asset_info['created'] = $shadow_asset->created;
1515  $asset_info['created_userid'] = $shadow_asset->created_userid;
1516  $asset_info['updated'] = $shadow_asset->updated;
1517  $asset_info['updated_userid'] = $shadow_asset->updated_userid;
1518  $asset_info['published'] = $shadow_asset->published;
1519  $asset_info['published_userid'] = $shadow_asset->published_userid;
1520  $asset_info['status_changed'] = $shadow_asset->status_changed;
1521  $asset_info['status_changed_userid'] = $shadow_asset->status_changed_userid;
1522  }
1523  } else {
1524  $asset_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($assetid));
1525  if (isset($asset_info[$assetid])) {
1526  $asset_info = $asset_info[$assetid];
1527  }
1528  $real_assetid = $assetid;
1529  }
1530 
1531  if (empty($asset_info)) {
1532  ob_start();
1533  echo '<span class="sq-backend-warning">Unknown asset (Id: #'.$assetid.')</span>';
1534  $contents = ob_get_clean();
1535  return $contents;
1536  }
1537 
1538  $asset_info['name'] = htmlspecialchars($asset_info['name'], ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1539 
1540  if (empty($screen)) {
1541  $screen_url = '';
1542  } else {
1543  $screen_url = $GLOBALS['SQ_SYSTEM']->am->getAssetBackendHref(Array($assetid => $screen));
1544  $screen_url = $screen_url[$assetid];
1545  }
1546 
1547  $type_name = $GLOBALS['SQ_SYSTEM']->am->getTypeInfo($asset_info['type_code'], 'name');
1548 
1549  ob_start();
1550  ?>
1551  <div id="asset-tag-line-<?php echo $assetid ?>-more-details" style="display:none;">
1552  <table cellspacing="0">
1553  <tr>
1554  <td class="sq-backend-table-cell" style="background-color: #<?php echo get_status_colour($asset_info['status']) ?>"><strong>Current Status:</strong></td>
1555  <td colspan="2" class="sq-backend-table-cell" style="background-color: #<?php echo get_status_colour($asset_info['status']) ?>"><i><?php echo get_status_description($asset_info['status']) ?></i></td>
1556  </tr>
1557  <tr>
1558  <td class="sq-backend-table-cell"><strong><?php echo translate('asset_type') ?>:</strong></td>
1559  <td colspan="2" class="sq-backend-table-cell"><?php echo get_asset_type_icon($asset_info['type_code']).' '.$type_name ?></td>
1560  </tr>
1561  <?php
1562  $headers = Array(
1563  'created' => 'Asset Created',
1564  'updated' => 'Last Updated',
1565  'published' => 'Last Published',
1566  'status_changed' => 'Status Last Changed',
1567  );
1568 
1569  foreach ($headers as $time_type => $header) {
1570  // If a time never happened (typically 'published')...
1571  if (!empty($asset_info[$time_type])) {
1572  $time_str = date('jS M Y g:ia', strtotime($asset_info[$time_type]));
1573 
1574  if ($asset_info[$time_type.'_userid'] == 0) {
1575  $user_name = 'System';
1576  } else {
1577  $user_name = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($asset_info[$time_type.'_userid']), Array('asset'), FALSE, 'name');
1578  if (empty($user_name) || !isset($user_name[$asset_info[$time_type.'_userid']]) || empty($user_name[$asset_info[$time_type.'_userid']])) {
1579  $user_name = '<span style="color: red">'.translate('unknown_or_deleted_user').'</span>';
1580  } else {
1581  $user_name = htmlspecialchars($user_name[$asset_info[$time_type.'_userid']], ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1582  }
1583  }
1584 
1585  $user_name = 'by '.$user_name;
1586  } else {
1587  $time_str = translate('never');
1588  $user_name = '&nbsp;';
1589  }
1590  ?><tr>
1591  <td class="sq-backend-table-cell" ><strong><?php echo $header ?>:</strong></td>
1592  <td class="sq-backend-table-cell" ><?php echo $time_str ?></td>
1593  <td class="sq-backend-table-cell" ><?php echo $user_name ?></td>
1594  </tr><?php
1595  }
1596  ?></table>
1597  </div>
1598 
1599  <?php
1600  // LINEAGES BOX
1601  $lineages = $GLOBALS['SQ_SYSTEM']->am->getLinkLineages($assetid, 5, NULL, 'name', TRUE);
1602 
1603  // start an inner buffer for the lineages popup
1604  ob_start();
1605  ?>
1606  <div id="asset-tag-line-<?php echo $assetid ?>-lineages" style="display:none">
1607  <table><?php
1608  foreach ($lineages as $lineage_key => $lineage) {
1609  if ($lineage['link_type'] & SQ_SC_LINK_BACKEND_NAV) {
1610  $lineage_assetids = array_keys($lineage['lineage']);
1611  $lineage_assetids[] = str_replace('\\', '\\\\', $assetid);
1612 
1613  $lineage_names = $lineage['lineage'];
1614 
1615  // If we have too many in the lineage, we need to add '...' between first
1616  // 2 and last 2 - including the asset itself
1617  if (count($lineage['lineage']) > 3) {
1618  $lineage_names = $lineage['lineage'];
1619  array_splice($lineage_names, 2, -1, Array('...'));
1620  }
1621 
1622  foreach ($lineage_names as $id => $name){
1623  $lineage_names[$id] = htmlspecialchars($name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1624  }
1625 
1626  $lineage_names[$assetid] = $asset_info['name'];
1627  $lineages_onclick = _asset_locator_onclick($lineage_assetids, TRUE);
1628  ?><tr>
1629  <td class="sq-backend-table-cell" ><a href="#" onclick="<?php echo $lineages_onclick; ?>"><?php echo implode(' &gt; ', $lineage_names) ?></a></td>
1630  </tr><?php
1631  } else {
1632  unset($lineages[$lineage_key]);
1633  }
1634  }
1635  ?></table>
1636  </div>
1637  <?php
1638  $lineages_div = ob_get_clean();
1639 
1640  // If there is more than one lineage, then provide the popup, otherwise
1641  // discard it and the icon becomes a direct selection
1642  if (count($lineages) > 1) {
1643  echo $lineages_div;
1644  ?><div id="asset-tag-line-<?php echo $assetid ?>-cancel-icon" style="display:none"><?php
1645  sq_print_icon(sq_web_path('data').'/asset_types/bodycopy/images/icons/delete.png', 16, 16, translate('cancel'), translate('cancel'), ' style="border:none"');
1646  ?></div><?php
1647  $lineages_onclick = 'tooltip.show(this, document.getElementById(\'asset-tag-line-'.str_replace('\\', '\\\\', $assetid).'-lineages\').innerHTML, \''.translate('lineages').'\', document.getElementById(\'asset-tag-line-'.str_replace('\\', '\\\\', $assetid).'-cancel-icon\').innerHTML)';
1648  $lineages_name = translate('show_lineages');
1649  } else if (count($lineages) == 1) {
1650  sort($lineages);
1651  $lineage_names = $lineages[0]['lineage'];
1652  foreach ($lineage_names as $id => $name){
1653  $lineage_names[$id] = htmlspecialchars($name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1654  }
1655  $lineage_names[$assetid] = $asset_info['name'];
1656 
1657  $lineages_onclick = _asset_locator_onclick($lineage_assetids, FALSE);
1658  $lineages_name = translate('show_in_asset_map');
1659  }
1660 
1661  echo sq_print_icon(sq_web_path('lib').'/web/images/icons/info.png', 16, 16, '', '', ' align="absmiddle" onmouseover="tooltip.show(this, document.getElementById(\'asset-tag-line-'.str_replace('\\', '\\\\', $assetid).'-more-details\').innerHTML, \'More Info\');" onmouseout="tooltip.hide();"');
1662 
1663  if (count($lineages) > 0) {
1664  echo sq_print_icon(sq_web_path('lib').'/web/images/icons/asset_locator.png', 16, 16, $lineages_name, $lineages_name, ' class="clickable" align="absmiddle" onclick="'.$lineages_onclick.'"');
1665  }
1666 
1667  // Screen parameter now supports javascript code to be added to the
1668  // onclick event in lieu of actually going to a screen
1669  if (preg_match('/^javascript:/i', $screen)) {
1670  $js = preg_replace('/^javascript:/i', '', $screen);
1671  if (substr($js, -1) != ';') $js .= ';';
1672  }
1673 
1674  if (!empty($js)) {
1675  echo '<a href="#" onclick="'.$js.' return false;">';
1676  } else if (!empty($screen_url)) {
1677  echo '<a href="'.$screen_url.'">';
1678  }
1679  echo $asset_info['name'];
1680 
1681  if (!empty($js) || !empty($screen_url)) {
1682  echo '</a>';
1683  }
1684 
1685  echo ' (Id: #'.$assetid.') ';
1686 
1687  $contents = ob_get_clean();
1688 
1689  return $contents;
1690 
1691 }//end get_asset_tag_line()
1692 
1693 
1703 function _asset_locator_onclick($lineage_assetids, $tooltip_hide)
1704 {
1705  // Logic:
1706  // 1. Invoking from a WYSIWYG popup itself (WYSIWYG search results)
1707  // => target is the popup, to target the simple asset map
1708  // 2. Invoking from main window when a WYSIWYG popup is active
1709  // => target is the popup (simple asset map), BUT need to focus it
1710  // 3. Invoking from a popup which is not a sq_wysiwyg_dialog, e.g. keywords page popup
1711  // => target is the main window (opener) and no need to focus it
1712  // 4. Invoking from main window, no WYSWIYG popup
1713  // => target is the sidenav window, to target the main asset map
1714  $onclick = 'if (self.name == \'sq_wysiwyg_popup_main\') {
1715  am = self;
1716  } else if (self.name == \'hipo_job\') {
1717  am = opener;
1718  } else if ((typeof sq_wysiwyg_dialog != \'undefined\') && (sq_wysiwyg_dialog != null) && (!sq_wysiwyg_dialog.closed)) {
1719  am = sq_wysiwyg_dialog.frames[\'sq_wysiwyg_popup_main\'];
1720  am.focus();
1721  } else if ((typeof opener != \'undefined\') && (opener != null) && (!opener.closed)) {
1722  am = opener.parent.top.frames[\'sq_sidenav\'];
1723  } else {
1724  am = parent.top.frames[\'sq_sidenav\'];
1725  }
1726  am.asset_locator_start(\''.get_asset_lineage_sort_order($lineage_assetids).'\');';
1727 
1728  if ($tooltip_hide) $onclick .= 'tooltip.hide();';
1729  $onclick .= 'return false;';
1730  return $onclick;
1731 
1732 }//end _asset_locator_onclick()
1733 
1734 
1744 function get_asset_type_icon($type_code, $extra='')
1745 {
1746  $type_name = $GLOBALS['SQ_SYSTEM']->am->getTypeInfo($type_code, 'name');
1747 
1748  return sq_print_icon($GLOBALS['SQ_SYSTEM']->am->getAssetIconURL($type_code), 16, 16, $type_name, $type_name, ' align="absmiddle" '.$extra);
1749 
1750 }//end get_asset_type_icon()
1751 
1752 
1761 function get_asset_status_icon($status)
1762 {
1763  require_once dirname(__FILE__).'/general_occasional.inc';
1764  $status_name = get_status_description($status);
1765  $status_colour = get_status_colour($status);
1766 
1767  return '<img src="'.sq_web_path('lib').'/web/images/blank.gif" width="10" height="10" alt="'.$status_name.'" title="'.$status_name.'" align="absmiddle" style="margin: 2px; border: 1px solid #ccc; background-color: #'.$status_colour.'" /> ';
1768 
1769 }//end get_asset_status_icon()
1770 
1771 
1787 function asset_locator_js($asset_lineage=Array(),$map_frame='sq_sidenav', $new_window=FALSE)
1788 {
1789  $finder_frame = ($new_window || empty($map_frame)) ? 'parent.top' : 'parent.frames["sq_main"]';
1790  if (!empty($map_frame)) {
1791  $map_frame = trim('parent.top.frames[\''.$map_frame.'\']', '.');
1792  } else {
1793  $map_frame = 'top';
1794  }
1795 
1796  $js_code = $map_frame.'.asset_locator_start(\''.get_asset_lineage_sort_order($asset_lineage).'\');';
1797  return $js_code;
1798 
1799 }//end asset_locator_js()
1800 
1801 
1811 function get_asset_lineage_sort_order($asset_lineage=Array())
1812 {
1813  if ($asset_lineage[0] == 1) {
1814  array_shift($asset_lineage);
1815  }
1816 
1817  $asset_count = count($asset_lineage);
1818  $sort_orders = Array();
1819  $link = $GLOBALS['SQ_SYSTEM']->am->getLinkByAsset(1, $asset_lineage[0]);
1820  if (isset($link['sort_order'])) {
1821  $sort_orders[0] = $link['sort_order'];
1822  }
1823 
1824  for ($i = 0; $i < $asset_count-1; $i++) {
1825  $sort_order = -1;
1826  // get the link between two assets
1827  if (strpos($asset_lineage[$i],':') === FALSE) {
1828  $link = $GLOBALS['SQ_SYSTEM']->am->getLinkByAsset($asset_lineage[$i], $asset_lineage[$i+1]);
1829  if (!empty($link)) {
1830  if (isset($link['sort_order']) && $link['sort_order']!='') {
1831  $sort_order = $link['sort_order'];
1832  }
1833  }
1834  }
1835  $sort_orders[] = $sort_order;
1836  }
1837 
1838  return implode('|',$asset_lineage).'~'.implode('|',$sort_orders);
1839 
1840 }//end get_asset_lineage_sort_order()
1841 
1842 
1849 function get_available_global_keywords()
1850 {
1851  $ret = Array(
1852  'globals_user_' => 'Global Keywords - Current User',
1853  'globals_get_' => 'Global Keywords - Get Parameters',
1854  'globals_post_' => 'Global Keywords - Post Parameters',
1855  'globals_session_' => 'Global Keywords - Session',
1856  'globals_cookie_' => 'Global Keywords - Cookie',
1857  'globals_server_' => 'Global Keywords - Server',
1858  'globals_date' => 'Global Keywords - Current Date and Time',
1859  'globals_site_' => 'Global Keywords - Current Site',
1860  'globals_asset_' => 'Global Keywords - Front End Asset',
1861  'globals_snippet_' => 'Global Keywords - Snippet',
1862  'globals_icon_' => 'Global Keywords - Type Icon',
1863  );
1864 
1865  return $ret;
1866 
1867 }//end get_available_global_keywords()
1868 
1869 
1878 function replace_global_keywords(&$text)
1879 {
1880  require_once SQ_FUDGE_PATH.'/general/text.inc';
1881  for ($c = 0; ($c < 2 && !(stripos($text, '%globals_') === FALSE)); $c++) {
1882  $keywords = retrieve_keywords_replacements($text);
1883  if (!empty($keywords)) {
1884  $replacements = Array();
1885  foreach ($keywords as $keyword) {
1886  $full_keyword = $keyword;
1887  $keyword = parse_keyword($keyword, $modifiers);
1888  $contextid = extract_context_modifier($modifiers);
1889 
1890  if ($contextid !== NULL) {
1891  $GLOBALS['SQ_SYSTEM']->changeContext($contextid);
1892  }
1893 
1894  if (0 === strpos($keyword, 'globals_')) {
1895  // Default replacement for global keywords is blank string
1896  $replacements[$full_keyword] = '';
1897  if (0 === strpos($keyword, 'globals_user_')) {
1898  $user_keyword = 'asset_'.substr($keyword, 13);
1899  $user_replacement = $GLOBALS['SQ_SYSTEM']->user->getKeywordReplacement($user_keyword);
1900  if ((string)$user_replacement != "%$user_keyword%") {
1901  $replacements[$full_keyword] = $user_replacement;
1902  }
1903  }
1904  if (0 === strpos($keyword, 'globals_get_')) {
1905  $sub_keyword = substr($keyword, 12);
1906  $replacements[$full_keyword] = clean_keyword_value(array_get_index($_GET, $sub_keyword, ''), $modifiers);
1907  }
1908  if (0 === strpos($keyword, 'globals_post_')) {
1909  $sub_keyword = substr($keyword, 13);
1910  $replacements[$full_keyword] = clean_keyword_value(array_get_index($_POST, $sub_keyword, ''), $modifiers);
1911  }
1912  if (0 === strpos($keyword, 'globals_session_')) {
1913  $sub_keyword = substr($keyword, 16);
1914  $replacements[$full_keyword] = clean_keyword_value(isset($_SESSION[SQ_SESSION_SANDBOX_INDEX][$sub_keyword]) ? $_SESSION[SQ_SESSION_SANDBOX_INDEX][$sub_keyword] : '', $modifiers);
1915  }
1916  if ((0 === strpos($keyword, 'globals_cookie_')) && (0 !== strpos($keyword, 'globals_cookie_SQ_'))) {
1917  $sub_keyword = substr($keyword, 15);
1918  $replacements[$full_keyword] = clean_keyword_value(array_get_index($_COOKIE, $sub_keyword, ''), $modifiers);
1919  }
1920  if (0 === strpos($keyword, 'globals_server_')) {
1921  $sub_keyword = strtoupper(substr($keyword, 15));
1922  if($sub_keyword !== 'HTTP_COOKIE') {
1923  $replacements[$full_keyword] = array_get_index($_SERVER, $sub_keyword, '');
1924  if (!is_scalar($replacements[$full_keyword])) {
1925  $replacements[$full_keyword] = '';
1926  }
1927  }
1928  }
1929  if (0 === strpos($keyword, 'globals_date')) {
1930  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
1931  $date_keyword = readable_datetime();
1932  $formatting = substr($keyword, 12);
1933  $format = ltrim($formatting, '_');
1934  if ($format == 'readable') {
1935  $date_keyword = readable_datetime();
1936  } else {
1937  if (!empty($format)) {
1938  $date_keyword = date($format);
1939  }//end if
1940  }//end if
1941  $replacements[$full_keyword] = $date_keyword;
1942  }
1943  if (0 === strpos($keyword, 'globals_icon')) {
1944  $type = substr($keyword, 12);
1945  $type = ltrim($type, '_');
1946  $type_icon_replace = '';
1947  $type_icon_url = $GLOBALS['SQ_SYSTEM']->am->getAssetIconURL($type);
1948  list($base_url, $type_icon_loc) = explode('__data/', $type_icon_url);
1949  if (file_exists(SQ_DATA_PATH.'/public/'.$type_icon_loc)) {
1950  $type_icon_replace = sq_get_icon($type_icon_url, 16, 16, $type);
1951  }//end if
1952  $replacements[$full_keyword] = $type_icon_replace;
1953  }//end if
1954 
1955  if (0 === strpos($keyword, 'globals_site_')) {
1956  $site_keyword = 'asset_'.substr($keyword, 13);
1957  preg_match('|(.*):([0-9]+)$|',$site_keyword,$matches);
1958  // We must find the site before we can replace these keywords
1959  $site = NULL;
1960  if(empty($matches[2])) {
1961  if ($GLOBALS['SQ_SYSTEM']->isGlobalDefineSet('CURRENT_SITE')) {
1962  $site = $GLOBALS['SQ_SYSTEM']->getGlobalDefine('CURRENT_SITE');
1963  } else {
1964  if ($GLOBALS['SQ_SYSTEM']->isGlobalDefineSet('CURRENT_ASSET')) {
1965  $asset_url = $GLOBALS['SQ_SYSTEM']->getGlobalDefine('CURRENT_ASSET')->getURL();
1966  $protocol_pos = strpos($asset_url, '://');
1967  if ($protocol_pos !== FALSE) {
1968  $asset_url = substr($asset_url, $protocol_pos + 3);
1969  }
1970  } else {
1971  $asset_url = current_url(FALSE, TRUE);
1972  }
1973  $asset_lineage = $GLOBALS['SQ_SYSTEM']->am->getLineageFromURL(NULL, $asset_url);
1974 
1975  $site_assetid = 0;
1976  foreach ($asset_lineage as $asset_link) {
1977  $asset_type = $asset_link['type_code'];
1978  if ($asset_type == 'site' || $GLOBALS['SQ_SYSTEM']->am->isTypeDecendant($asset_type, 'site')) {
1979  $site_assetid = $asset_link['assetid'];
1980  break;
1981  }
1982  }
1983  if (!empty($site_assetid)) {
1984  $site = $GLOBALS['SQ_SYSTEM']->am->getAsset($site_assetid);
1985  }
1986  }//end if
1987  if (!is_null($site)) {
1988  $site_replacement = $site->getKeywordReplacement($site_keyword);
1989  if ((string)$site_replacement != "%$site_keyword%") {
1990  $replacements[$full_keyword] = $site_replacement;
1991  }
1992  }
1993  } else {
1994  $asset_exist = $GLOBALS['SQ_SYSTEM']->am->assetExists($matches[2]);
1995  if ($asset_exist === TRUE) {
1996  $site = $GLOBALS['SQ_SYSTEM']->am->getAsset($matches[2]);
1997  }
1998  if (!is_null($site)) {
1999  $site_replacement = $site->getKeywordReplacement($matches[1]);
2000  if ((string)$site_replacement != "%$site_keyword%") {
2001  $replacements[$full_keyword] = $site_replacement;
2002  }
2003  }
2004  }//end if
2005  }//end if
2006 
2007 
2008  if (0 === strpos($keyword, 'globals_asset_')) {
2009  $asset_keyword = 'asset_'.substr($keyword, 14);
2010  preg_match('|(.*):([0-9]+)$|',$asset_keyword,$matches);
2011 
2012  if (empty($matches[2])) {
2013  $asset_replacement = '%'.$asset_keyword.'%';
2014 
2015  $current_asset = NULL;
2016  if ($GLOBALS['SQ_SYSTEM']->isGlobalDefineSet('CURRENT_ASSET')) {
2017  $current_asset = $GLOBALS['SQ_SYSTEM']->getGlobalDefine('CURRENT_ASSET', NULL);
2018  } else {
2019  if (SQ_IN_LIMBO) {
2020  if (isset($_REQUEST['limbo_assetid'])) {
2021  $current_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset((int)$_REQUEST['limbo_assetid']);
2022  } else {
2023  $current_asset = $GLOBALS['SQ_SYSTEM']->am->getAssetFromURL();
2024  }
2025  } else {
2026  $current_asset = $GLOBALS['SQ_SYSTEM']->frontend_asset;
2027  }
2028  }
2029 
2030  if ($current_asset) {
2031  $asset_replacement = $current_asset->getKeywordReplacement($asset_keyword);
2032  }
2033 
2034  if ((string)$asset_replacement != "%$asset_keyword%") {
2035  $replacements[$full_keyword] = $asset_replacement;
2036  }
2037  } else {
2038  $asset_exist = $GLOBALS['SQ_SYSTEM']->am->assetExists($matches[2]);
2039  if ($asset_exist === TRUE) {
2040  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($matches[2]);
2041  if ($asset->readAccess()) {
2042  // if the keywords is %globals_asset_contents*% replace them here
2043  // dont outsource it to asset.inc
2044  if (0 === strpos($asset_keyword, 'asset_contents')) {
2045  $asset_keyword = preg_replace( '|:([0-9]+)$|', '', $asset_keyword);
2046  $this_url = preg_replace('/https?:\/\//', '', $asset->getURL());
2047  if (0 === strpos($asset_keyword, 'asset_contents_raw')) {
2048 
2049  ob_start();
2050  // get the pront end of the asset but dont worry abt any errors here
2051  $asset->printBody();
2052  $content = ob_get_contents();
2053  ob_end_clean();
2054  $replacements[$full_keyword] = $content;
2055 
2056  } else if ($asset_keyword == 'asset_contents') {
2057 
2058  // get the front end of the asset
2059  $this_paint_layout = $asset->getCurrentPaintLayoutName();
2060  $layout_id = $GLOBALS['SQ_SYSTEM']->am->getValueFromURL($this_url, $this_paint_layout);
2061  ob_start();
2062  if (!$layout_id) {
2063  $asset->printBodyWithPaintLayout();
2064  } else {
2065  $asset->printBodyWithPaintLayout($layout_id);
2066  }
2067  $content = ob_get_contents();
2068  ob_end_clean();
2069  $replacements[$full_keyword] = $content;
2070 
2071  } else if (0 === strpos ($asset_keyword, 'asset_contents_paint_layout_id')) {
2072 
2073  $layout_id = str_replace('asset_contents_paint_layout_id_', '', $asset_keyword);
2074  ob_start();
2075  if (!$layout_id) {
2076  $asset->printBodyWithPaintLayout();
2077  } else {
2078  $asset->printBodyWithPaintLayout($layout_id);
2079  }
2080  $content = ob_get_contents();
2081  ob_end_clean();
2082  $replacements[$full_keyword] = $content;
2083 
2084  } else if (0 === strpos ($asset_keyword, 'asset_contents_paint_layout_name')) {
2085 
2086  $layout_name = str_replace('asset_contents_paint_layout_name_', '', $asset_keyword);
2087 
2088  // if user has not mentioned if it is a user defined or default frontend
2089  // assume it is user defined
2090  if (strpos($layout_name, 'paint_layout::user::') === FALSE && strpos($layout_name, 'paint_layout::system::frontend') === FALSE) {
2091  $layout_name = 'paint_layout::user::'.$layout_name;
2092  }
2093  $layout_id = $GLOBALS['SQ_SYSTEM']->am->getValueFromURL($this_url, $layout_name);
2094  ob_start();
2095  if (!$layout_id) {
2096  $asset->printBodyWithPaintLayout();
2097  } else {
2098  $asset->printBodyWithPaintLayout($layout_id);
2099  }
2100  $content = ob_get_contents();
2101  ob_end_clean();
2102  $replacements[$full_keyword] = $content;
2103 
2104  }
2105 
2106  }
2107  $asset_replacement = $asset->getKeywordReplacement($matches[1]);
2108  if ((string)$asset_replacement != "%$matches[1]%") {
2109  $replacements[$full_keyword] = $asset_replacement;
2110  }
2111  }
2112  }
2113  }
2114  }//end if
2115  if (0 === strpos($keyword, 'globals_snippet_')) {
2116  $replacements[$full_keyword] = '';
2117  if ($GLOBALS['SQ_SYSTEM']->am->installed('content_type_snippet')) {
2118  $snippet_info = explode('_', $keyword);
2119  if (is_numeric($snippet_info[2])) {
2120  // is this snippet id valid and current?
2121  $all_snippets = $GLOBALS['SQ_SYSTEM']->am->getSnippetKeywords(TRUE);
2122  if (in_array($snippet_info[2], array_keys($all_snippets))) {
2123  $snippet_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($snippet_info[2]);
2124  if (!is_null($snippet_asset)) {
2125  // printBody will handle the permission
2126  ob_start();
2127  $snippet_asset->printBody();
2128  $replacement = ob_get_contents();
2129  ob_end_clean();
2130  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($snippet_asset);
2131  $replacements[$full_keyword] = $replacement;
2132  }
2133  }
2134  }
2135  }
2136  }//end if
2137  if (0 === strpos($keyword, 'globals_random')) {
2138  if ($keyword == 'globals_random') {
2139  $replacements[$full_keyword] = rand();
2140  } else {
2141  $sub_keyword = substr($keyword, 14);
2142  if (preg_match('/^_(\d+)_(\d+)$/', $sub_keyword, $matches)) {
2143  $replacements[$full_keyword] = rand((int)$matches[1], (int)$matches[2]);
2144  }
2145  }
2146  }//end if
2147  if ($keyword == 'globals_context') {
2148  $context_name = '';
2149  // get current context ID
2150  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
2151  if (!is_null($contextid)) {
2152  // get all available contexts and find the name of current context from ID
2153  $all_contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
2154  if (isset($all_contexts[$contextid]['name'])) {
2155  $context_name = $all_contexts[$contextid]['name'];
2156  }
2157  }
2158 
2159  $replacements[$full_keyword] = $context_name;
2160  }//end if
2161 
2162  apply_keyword_modifiers($replacements[$full_keyword], $modifiers);
2163 
2164  }//end if is global keyword
2165 
2166 
2167  if ($contextid !== NULL) {
2168  $GLOBALS['SQ_SYSTEM']->restoreContext();
2169  }
2170 
2171  }//end foreach keyword
2172  replace_keywords($text, $replacements);
2173  }//end if
2174 
2175  }//end for
2176  return $text;
2177 
2178 }//end replace_global_keywords()
2179 
2180 
2202 function extract_context_modifier(&$modifiers, $return_part='id')
2203 {
2204  $context = NULL;
2205  foreach (array_keys($modifiers) as $modifier_key) {
2206  if ($modifiers[$modifier_key]['modifier'] === 'context') {
2207  if (isset($modifiers[$modifier_key]['args']) === TRUE) {
2208  $context = $modifiers[$modifier_key]['args'][0];
2209  }
2210  // remove the context modifier no matter what
2211  unset($modifiers[$modifier_key]);
2212  }
2213  }
2214 
2215  if ($context !== NULL) {
2216  $contextid = MatrixDAL::executeOne('core', 'getContextByName', Array('name' => $context));
2217  if ($contextid === FALSE) $contextid = NULL;
2218  } else {
2219  $contextid = NULL;
2220  }
2221 
2222  if ($return_part === 'name') {
2223  return $context;
2224  } else if ($return_part === 'both') {
2225  return Array(
2226  'id' => $contextid,
2227  'name' => $context,
2228  );
2229  } else {
2230  // return ID by default
2231  return $contextid;
2232  }
2233 
2234 }//end extract_context_modifier()
2235 
2236 
2247 function clean_keyword_value($keyword_value, $modifiers)
2248 {
2249  // If modifiers are being used we assume they're doing their own escaping
2250  if (!empty($modifiers)) {
2251  return $keyword_value;
2252  } else if (!is_scalar($keyword_value)) {
2253  // Only scalars are accepted
2254  $keyword_value = '';
2255  } else {
2256  // whitelist of characters that will not be stripped out,
2257  // for some security
2258  $safe_list = 'A-Za-z0-9\.\-\_\%\$\(\)\=\[\] ';
2259  $keyword_value = preg_replace('/[^'.$safe_list.']+/', '', (string)$keyword_value);
2260  }
2261 
2262  return $keyword_value;
2263 
2264 }//end clean_keyword_value()
2265 
2266 
2284 function quick_hipo($callback_assetid, $callback_function, $items, $settings, $fail_on_error=FALSE)
2285 {
2286  $hh = $GLOBALS['SQ_SYSTEM']->getHipoHerder();
2287  $vars = Array(
2288  'callback_assetid' => $callback_assetid,
2289  'callback_function' => $callback_function,
2290  'items' => $items,
2291  'settings' => $settings,
2292  'fail_on_error' => $fail_on_error,
2293  );
2294  return $hh->queueHipo('hipo_job_quick_hipo', $vars);
2295 
2296 }//end quick_hipo()
2297 
2298 
2309 function do_redirect($url, $message=NULL, $timeout=0)
2310 {
2311  if ($timeout || $message || headers_sent()) {
2312  // Javascript Redirect
2313  if (is_null($message)) {
2314  $message = translate('redirecting_you_to', htmlentities($url, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET));
2315  }
2316  ?>
2317  <html>
2318  <head />
2319  <body>
2320  <p><?php echo $message; ?></p>
2321  <script type="text/javascript"><!--
2322  //<![CDATA[
2323  <?php
2324  if ($timeout) {
2325  ?>
2326  setTimeout("self.location = '<?php echo str_replace("'", "\'", $url); ?>'", <?php echo $timeout * 1000; ?>);
2327  <?php
2328  } else {
2329  ?>
2330  self.location = '<?php echo str_replace("'", "\'", $url); ?>';
2331  <?php
2332  }
2333  ?>
2334  //]]> -->
2335  </script>
2336  <br />
2337  </body>
2338  </html>
2339  <?php
2340  } else {
2341  // Header Redirect
2342  header('Location: '.$url);
2343  }
2344  exit(1);
2345 
2346 }//end do_redirect()
2347 
2348 
2358 function get_class_lower($object)
2359 {
2360  return strtolower(get_class($object));
2361 
2362 }//end get_class_lower()
2363 
2364 
2373 function clean_div_attribute($attribute)
2374 {
2375  // do not allow PHP tags or whitespace
2376  $pattern = '/(?:<\?|\?>)+|\s+/';
2377  $replacement = '_';
2378  $attribute = strtolower(preg_replace($pattern, $replacement, $attribute));
2379  return str_replace('"', '&quot;', $attribute);
2380 
2381 }//end clean_div_attribute()
2382 
2383 
2393 function xml_entity_decode($string, $decode_html_entities = TRUE)
2394 {
2395  if ($decode_html_entities) {
2396  $string = html_entity_decode($string, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
2397  }
2398  $string = str_replace('&#124;', '|', $string);
2399  $string = str_replace('&apos;', "'", $string);
2400  $string = str_replace('&#42;', '*', $string);
2401  $string = str_replace('&#92;', '\\', $string);
2402  $string = str_replace('&#126;', '~', $string);
2403  $string = str_replace('&#96;', '`', $string);
2404  $string = str_replace('&#94;', '^', $string);
2405 
2406  return $string;
2407 
2408 }//end xml_entity_decode()
2409 
2410 
2420 function filter_content($attr_value)
2421 {
2422  $unser_str = @unserialize($attr_value);
2423  if ($unser_str !== FALSE) {
2424  if (is_array($unser_str)){
2425  try {
2426  $success = array_walk($unser_str, 'recursive_content_filter');
2427  if (!$success) return FALSE;
2428  $attr_value = serialize($unser_str);
2429  } catch (Exception $e) {
2430  return FALSE;
2431  }
2432  } else if (is_scalar($unser_str)){
2433  $unser_str = simple_content_filter($unser_str);
2434  if ($unser_str === FALSE) return FALSE;
2435  $attr_value = serialize($unser_str);
2436  }
2437  } else if (is_scalar($attr_value)) {
2438  $attr_value = simple_content_filter($attr_value);
2439  if ($attr_value === FALSE) return FALSE;
2440  } else if (is_array($attr_value)) {
2441  try {
2442  $success = array_walk($attr_value, 'recursive_content_filter');
2443  if (!$success) return FALSE;
2444  } catch (Exception $e) {
2445  return FALSE;
2446  }
2447  }
2448 
2449  return $attr_value;
2450 
2451 }//end filter_content()
2452 
2453 
2463 function simple_content_filter($attr_value)
2464 {
2465  $reg = "%<\/?script ?[^>]*>%i";
2466  $attr_value = preg_replace($reg, "", $attr_value);
2467  if ($attr_value === NULL) return FALSE;
2468 
2469  $keywords = extract_keywords($attr_value);
2470  foreach ($keywords as $keyword){
2471  $attr_value = str_ireplace("%$keyword%", "", $attr_value);
2472  if ($attr_value === NULL) return FALSE;
2473  }
2474  //decode first to avoid double encoding
2475  $attr_value = htmlspecialchars_decode($attr_value, ENT_COMPAT);
2476  $attr_value = htmlspecialchars($attr_value, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
2477 
2478  return $attr_value;
2479 
2480 }//end simple_content_filter()
2481 
2482 
2493 function recursive_content_filter(&$item)
2494 {
2495  //recursive: could not use array_walk_recursive because of a bug in PHP 5.2
2496  if(is_array($item)){
2497  $success = array_walk($item, __FUNCTION__);
2498  if (!$success) throw new Exception('Content Filtering Failed.');
2499  } else {
2500  $unser_item = @unserialize($item);
2501  if ($unser_item !== FALSE) {
2502  if (is_array($unser_item)){
2503  $success = array_walk($unser_item, __FUNCTION__);
2504  if (!$success) throw new Exception('Content Filtering Failed.');
2505  $item = serialize($unser_item);
2506  } else if (is_scalar($unser_item)){
2507  $clean = simple_content_filter($unser_item);
2508  if ($clean === FALSE) throw new Exception('Content Filtering Failed.');
2509  $item = serialize($clean);
2510  }
2511  } else {
2512  if (!empty($item)) {
2513  $item = simple_content_filter($item);
2514  if ($item === FALSE) throw new Exception('Content Filtering Failed.');
2515  }
2516  }
2517  }//end if
2518 
2519 }//end recursive_content_filter()
2520 
2521 
2530 function file_mime_type($filename)
2531 {
2532  $mime_type = '';
2533 
2534  if (class_exists('finfo')) {
2535  $finfo = new finfo(FILEINFO_MIME);
2536  $mime_info = explode(';', $finfo->file($filename));
2537  $mime_type = $mime_info[0];
2538 
2539  } else if (function_exists('mime_content_type')) {
2540  $mime_type = mime_content_type($filename);
2541 
2542  } else {
2543  $ext_pos = strrpos($filename, '.');
2544  if ($ext_pos !== FALSE) {
2545  require SQ_FUDGE_PATH.'/standards_lists/mime_types.inc';
2546  $mime_type = array_get_index($standards_lists_mime_types, substr($filename, $ext_pos + 1), '');
2547  }
2548  }
2549 
2550  return $mime_type;
2551 
2552 }//end file_mime_type()
2553 
2554 
2572 function fetch_url($url='', $options=array(), $headers=array(), $use_proxy=TRUE)
2573 {
2574  static $_proxies_loaded = FALSE;
2575  static $_redirects = 0;
2576 
2577  $maxredirects = 5;
2578  if (isset($options['MAXREDIRS']) === TRUE) {
2579  $maxredirects = $options['MAXREDIRS'];
2580  }
2581 
2582  $curl_res = curl_init($url);
2583 
2584  // by default, we only allow http, https, ftp, ftps protocol. file protocol is very bad
2585  if(defined('CURLOPT_PROTOCOLS')) {
2586  curl_setopt($curl_res, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS);
2587  }
2588  else {
2589  if(strpos($url, ':') !== FALSE && !preg_match('/^(http)|(ftp)/i', $url)) {
2590  trigger_error('protocol not supported:'.$url);
2591  return FALSE;
2592  }
2593  }
2594 
2595  foreach ($options as $option => $value) {
2596  $option = strtolower($option);
2597  if ($option == 'proxy' && is_array($value) === TRUE) {
2598  continue;
2599  }
2600  if ($option == 'http_authentication' && is_array($value) === TRUE) {
2601  continue;
2602  }
2603  curl_setopt($curl_res, constant('CURLOPT_'.strtoupper($option)), $value);
2604  }
2605 
2606  if (is_array($headers) === FALSE) {
2607  $headers = array($headers);
2608  }
2609 
2610  if (empty($headers) === FALSE) {
2611  curl_setopt($curl_res, CURLOPT_HTTPHEADER, $headers);
2612  }
2613 
2614  if (isset($options['http_authentication']) === TRUE) {
2615  $auth = $options['http_authentication'];
2616  if (isset($auth['username']) === TRUE && isset($auth['password']) === TRUE) {
2617  curl_setopt($curl_res, CURLOPT_USERPWD, $auth['username'].':'.$auth['password']);
2618  }
2619  }
2620 
2621  $proxy_set = FALSE;
2622  if ($use_proxy === TRUE) {
2623  if ($_proxies_loaded === FALSE) {
2624  $proxy_auth_file = SQ_DATA_PATH.'/private/conf/proxy_authentication.inc';
2625  if (file_exists($proxy_auth_file) === TRUE) {
2626  require_once $proxy_auth_file;
2627  $_proxies_loaded = TRUE;
2628  }
2629  }
2630 
2631  if ($_proxies_loaded === TRUE && defined('SQ_PA_ENABLED') && SQ_PA_ENABLED) {
2632  $proxy = get_proxy_info_for_url($url);
2633  if (empty($proxy['host']) === FALSE) {
2634  // Only set this proxytunnel option if we're going to a https url.
2635  // Otherwise you end up getting 405 errors.
2636  if (substr($url, 0, 5) == 'https') {
2637  curl_setopt($curl_res, CURLOPT_HTTPPROXYTUNNEL, TRUE);
2638  }
2639  curl_setopt($curl_res, CURLOPT_PROXY, $proxy['host']);
2640  if ($proxy['port']) {
2641  curl_setopt($curl_res, CURLOPT_PROXYPORT, $proxy['port']);
2642  }
2643  if (isset($options['proxy']) === TRUE) {
2644  if (isset($options['proxy']['user']) === TRUE &&
2645  isset($options['proxy']['password']) === TRUE) {
2646  curl_setopt($curl_res, CURLOPT_PROXYUSERPWD, $options['proxy']['user'].':'.$options['proxy']['password']);
2647  }
2648  } else {
2649  if ($proxy['user'] && $proxy['password']) {
2650  curl_setopt($curl_res, CURLOPT_PROXYUSERPWD, $proxy['user'].':'.$proxy['password']);
2651  }
2652  }
2653  $proxy_set = TRUE;
2654  }
2655  }//end if
2656  }
2657  if(!$proxy_set) curl_setopt($curl_res, CURLOPT_PROXY, NULL);
2658 
2659  $result = curl_exec($curl_res);
2660 
2661  $info = array(
2662  'errornumber' => curl_errno($curl_res),
2663  'errorstring' => curl_error($curl_res),
2664  'response' => $result,
2665  'curlinfo' => curl_getinfo($curl_res),
2666  );
2667 
2668  // If we're not sending back a resource, make sure we close the connection.
2669  // If we do, it'll be up to the calling code to deal with it.
2670  if (is_resource($result) === FALSE) {
2671  curl_close($curl_res);
2672 
2673  // Let's check if the request has a meta http-equiv refresh tag in there.
2674  // If it does, we need to handle that and possibly grab new content.
2675 
2676  // There's no tag?
2677  // Nice 'n easy.
2678  preg_match('!<meta\\s+([^>]*http-equiv\\s*=\\s*("Refresh"|\'Refresh\'|Refresh)[^>]*)>!is', $result, $matches);
2679  if (empty($matches) === TRUE) {
2680  return $info;
2681  }
2682 
2683  // Just a refresh, no redirect
2684  preg_match('!content\\s*=\\s*("[^"]+"|\'[^\']+\'|\\S+)!is', $matches[1], $urlMatches);
2685  if (empty($urlMatches) === TRUE) {
2686  return $info;
2687  }
2688 
2689  // Our redirect content should look like this:
2690  // content="0;url=http://www.example.com"
2691  // Get rid of quotes around the redirect content.
2692  $redirectContent = rtrim($urlMatches[1], '"');
2693  $redirectContent = rtrim($redirectContent, "'");
2694 
2695  // If there's no ; in the content, return.
2696  $parts = explode(';', $redirectContent);
2697  if (isset($parts[1]) === FALSE) {
2698  return $info;
2699  }
2700 
2701  // Check there's a url in the part we need.
2702  preg_match('/url\\s*=\\s*("[^"]+"|\'[^\']+\'|\\S+)/is', $parts[1], $urlMatches);
2703  if (empty($urlMatches) === TRUE) {
2704  return $info;
2705  }
2706 
2707  $redirectUrl = rtrim($urlMatches[1], '"');
2708  $redirectUrl = rtrim($redirectUrl, "'");
2709 
2710  // Make sure we're not in a redirect loop.
2711  // (page-1 redirects to page-2, which redirects to page-1).
2712  $_redirects++;
2713  if ($_redirects > $maxredirects || $redirectUrl == $url) {
2714  $info['errornumber'] = CURLE_TOO_MANY_REDIRECTS;
2715  $info['errorstring'] = 'Too many redirects. When following redirects, libcurl hit the maximum amount.';
2716  $info['response'] = '';
2717  $info['curlinfo'] = array();
2718  return $info;
2719  }
2720 
2721  if (isset($options['FOLLOWLOCATION']) === TRUE) {
2722  // If we're all good to go, get the new page and return it.
2723  $info = fetch_url($redirectUrl, $options, $headers, $use_proxy);
2724  return $info;
2725  }
2726 
2727  // Since it has a redirect in it, it'll be printed in the browser
2728  // and the browser can deal with it.
2729  // We don't need to deal with it ourselves.
2730  return $info;
2731  }
2732 
2733  return $info;
2734 }//end fetch_url()
2735 
2736 
2748 function get_proxy_info_for_url($page_url)
2749 {
2750  $alternatives = SQ_PA_ALTERNATIVES;
2751 
2752  if (trim($alternatives) !== '') {
2753  $alternatives = unserialize($alternatives);
2754  } else {
2755  $alternatives = Array();
2756  }
2757 
2758  // Back-up for if we don't have any alternatives
2759  $match = FALSE;
2760 
2761  foreach ($alternatives as $alternative) {
2762  // if the $alternative was just added it will not have any index defined so no point going further
2763  // and throw the PHP notices see bug #5326 trying to add an Alternative Proxy spits out PHP warnings
2764  if (empty($alternative)) continue;
2765 
2766  $pattern_url = $alternative['pattern_url'];
2767  switch ($alternative['pattern_type']) {
2768  case 'equals':
2769  $match = ($page_url == $pattern_url);
2770  break;
2771 
2772  case 'begins':
2773  // See if the pattern starts in exactly character 0
2774  $match = (strpos($page_url, $pattern_url) === 0);
2775  break;
2776 
2777  case 'ends':
2778  // See if the pattern starts at exactly the point where
2779  // it would fill up the end of the string
2780  $match = (strpos($page_url, $pattern_url) === (strlen($page_url) - strlen($pattern_url)));
2781  break;
2782 
2783  case 'contains':
2784  // All we need to see is if the pattern is included in the URL
2785  $match = (strpos($page_url, $pattern_url) !== FALSE);
2786  break;
2787 
2788  }//end switch
2789 
2790  // Invert if necessary
2791  if ($alternative['pattern_not']) $match = !$match;
2792 
2793  if ($match) {
2794  // We have a match; we'll use this and break out
2795  $proxy_host = $alternative['proxy_url'];
2796  $proxy_port = $alternative['proxy_port'];
2797  $proxy_user = $alternative['username'];
2798  $proxy_pass = base64_decode($alternative['password']);
2799  break;
2800  }
2801 
2802  }//end foreach
2803 
2804  if (!$match) {
2805  // Use the primary proxy if we can't find a match
2806  $proxy_host = SQ_PA_HOSTNAME;
2807  $proxy_port = SQ_PA_PORT;
2808  $proxy_user = SQ_PA_USERNAME;
2809  $proxy_pass = base64_decode(SQ_PA_PASSWORD);
2810  }
2811 
2812  return Array(
2813  'host' => $proxy_host,
2814  'port' => $proxy_port,
2815  'user' => $proxy_user,
2816  'password' => $proxy_pass,
2817  );
2818 
2819 }//end get_proxy_info_for_url()
2820 
2821 ?>