* @version $Revision: 2911 $ */ $global_thumb_count =0; /** * Logs execution time of script * if $CONF['log_script_timing'] isn't set, nothing happens * if $CONF['log_script_timing'] == 'file' timings are logged in the logs folder * if $CONF['log_script_timing'] == 'apache' timings are logged via apache */ function log_script_timing() { global $STARTTIME,$USER,$CONF; list($usec, $sec) = explode(' ',microtime()); $endtime = ((float)$usec + (float)$sec); $timetaken = sprintf('%0.4f', $endtime - $STARTTIME); if ($CONF['log_script_timing']=='file') { //%03.4f doesn't seem to work so we must add our own padding //this makes the output file easily sortable if ($timetaken<100) $timetaken='0'.$timetaken; if ($timetaken<10) $timetaken='0'.$timetaken; $logfile=$CONF['log_script_folder'].'/'.date('Ymd-H').'.log'; $h = @fopen($logfile,'a'); if ($h) { $time = date("i:s"); $logline = "$timetaken,$time,{$_SERVER['SCRIPT_URL']},{$_SERVER['REQUEST_METHOD']},\"{$_SERVER['QUERY_STRING']}\",{$_SERVER['REMOTE_ADDR']},{$USER->user_id},\"{$_SERVER['HTTP_REFERER']}\"\n"; fwrite($h,$logline); fclose($h); } } elseif($CONF['log_script_timing']=='apache') { @apache_note('php_timing', $timetaken); } } /** * Smarty block handler * Although it doesn't appear to do much, this is registered as a * non-caching block handler - anything between {dynamic}{/dynamic} will * not be cached */ function smarty_block_dynamic($param, $content, &$smarty) { if (!empty($param) && !empty($param['cached_user_id'])) { $smarty->assign('cached_user_id',$param['cached_user_id']); } return $content; } /** * Smarty Getamap linker * * Makes linking to OS maps easy {getamap gridref='TL0000' text='get a map'} */ function smarty_function_getamap($params) { global $CONF; $icon=empty($params['icon'])?"\"External":''; //get params $matches=array(); $gridref4=preg_replace('/^([A-Z]{1,3})\s*(\d{2,5})\s*(\d{2,5})$/i','$1$2$3',$params['gridref']); if (preg_match('/^document\./i', $gridref4)) { if (!empty($params['gridref2'])) $gridref4 .= ",'{$params['gridref2']}'"; return "{$params['text']}$icon"; } else if (preg_match('/^([A-Z]{1,3})(\d{4,10})$/i', $gridref4, $matches)) { if (!empty($params['text'])) $text=$params['text']; else $text=$params['gridref']; $gridref6=""; $coords=$matches[2]; $l=strlen($coords); switch ($l) { case 4: $gridref6=$matches[1].substr($coords,0,2)."5".substr($coords,2,2)."5"; break; default: $gridref6=$gridref4; } if (isset($params['title'])) $title=$params['title']; else $title="Ordnance Survey Get-a-Map for $gridref4"; return "$text$icon"; } else if (empty($gridref4)) { if (!empty($params['text'])) $text=$params['text']; else $text='OS Get-a-Map'; return "$text$icon"; } else { //error return $gridref4; } } /** * Smarty new window linker * * Provides centralised formatting of external links * href, title and text are the params here... */ function smarty_function_newwin($params) { global $CONF; //get params and use intelligent defaults... $href=str_replace(' ','+',trim($params['href'])); if (isset($params['text'])) $text=$params['text']; else $text=$href; if (isset($params['title'])) $title=$params['title']; else $title=$text; if (isset($params['nofollow'])) $title .= "\" rel=\"nofollow"; if (isset($params['onclick'])) $title .= "\" onclick=\"".$params['onclick']; return "$text". "\"New"; } /** * Smarty new window linker * * Provides centralised formatting of external links * href, title and text are the params here... */ function smarty_function_external($params) { global $CONF; //get params and use intelligent defaults... $href=str_replace(' ','+',$params['href']); if (strpos($href,'http://') !== 0) $href ="http://$href"; if (isset($params['text'])) $text=$params['text']; else $text=$href; if (isset($params['title'])) $title=$params['title']; else $title=$text; if (isset($params['nofollow'])) $title .= "\" rel=\"nofollow"; if ($params['target'] == '_blank') { return "$text". "\"External"; } else { return "$text". "\"External"; } } /** * Smarty gridimage thumbnail link * * given image id makes a nice thumbnail link */ function smarty_function_gridimage($params) { global $imageCredits; $image=new GridImage; $image->loadFromId($params['id']); if (isset($imageCredits[$image->realname])) { $imageCredits[$image->realname]++; } else { $imageCredits[$image->realname]=1; } $html='
'; $html.='
'; $title=$image->grid_reference.' : '.htmlentities2($image->title).' by '.htmlentities2($image->realname); $html.=''; $html.=$image->getThumbnail(213,160); $html.=''; $html.='
'; if (isset($params['extra'])) { if ($params['extra'] == '{description}') { if (!empty($image->comment)) { $desc = GeographLinks(nl2br(htmlentities2($image->comment))).'
by '.htmlentities2($image->realname).'
'; } else { $desc = ''; } } else { $desc = htmlentities2($params['extra']); } if (!empty($desc)) { $html.='
'.$desc.'
'; } } $html.='
'; return $html; } if (!function_exists('mb_ucfirst') && function_exists('mb_substr')) { function mb_ucfirst($string) { return mb_strtoupper(mb_substr($string, 0, 1)) . mb_substr($string, 1); } } function recaps($in) { $out = preg_replace('/(^|[ \/-])([^ \/-]{3,})/e','"$1".mb_ucfirst("$2")',mb_strtolower($in)); return stripslashes(preg_replace('/(^|\/)([^ \/-])/e','"$1".mb_strtoupper("$2")',$out)); } function smarty_function_place($params) { $place = $params['place']; $t = ''; if ($place['distance'] > 3) $t .= ($place['distance']-0.01)." km from "; elseif (!$place['isin']) $t .= "near to "; $place['full_name'] = _utf8_decode($place['full_name']); if (!ctype_lower($place['full_name'])) { $t .= "".recaps($place['full_name']).""; } else { $t .= "{$place['full_name']}"; } $t = str_replace(' And ',' and ',$t); if ($place['adm1_name'] && $place['adm1_name'] != $place['reference_name'] && $place['adm1_name'] != $place['full_name'] && !preg_match('/\(general\)$/',$place['adm1_name'])) { $parts = explode('/',$place['adm1_name']); if (!ctype_lower($parts[0])) { if (isset($parts[1]) && $parts[0] == $parts[1]) { unset($parts[1]); } $t .= ", ".recaps(implode('/',$parts)); } else { $t .= ", {$place['adm1_name']}"; } } elseif ($place['hist_county']) $t .= ", {$place['hist_county']}"; $t .= ", {$place['reference_name']}"; $tag = (isset($params['h3']))?'h3':'span'; $t2 = "<$tag"; if (!empty($params['h3']) && strlen($params['h3']) > 1) $t2 .= $params['h3']; if ($place['hist_county']) { $t2 .= " title=\"".substr($place['full_name'],0,12).": Historic County - {$place['hist_county']}"; if ($place['hist_county'] == $place['adm1_name']) $t2 .= ", and modern Administrative Area of the same name"; else $t2 .= ", modern Administrative Area - {$place['adm1_name']}"; $t2 .= "\""; } $t = $t2.">".$t.""; return $t; } function _utf8_decode($string) { $tmp = $string; $count = 0; while (mb_detect_encoding($tmp)=="UTF-8") { $tmp = utf8_decode($tmp); $count++; } for ($i = 0; $i < $count-1 ; $i++) { $string = utf8_decode($string); } return $string; } function smarty_function_linktoself($params) { $a = array(); $b = explode('?',$_SERVER['REQUEST_URI']); if (isset($b[1])) parse_str($b[1],$a); if ($params['value'] == 'null') { if (isset($a[$params['name']])) unset($a[$params['name']]); } else { $a[$params['name']] = $params['value']; } if (!empty($params['delete'])) { unset($a[$params['delete']]); } return htmlentities($_SERVER['SCRIPT_NAME'].count($a)?("?".http_build_query($a,'','&')):''); } /** * adds commas to thousendise a number */ function smarty_function_thousends($input,$decimals=0) { return number_format($input,$decimals); } function smarty_function_ordinal($i) { $units=$i%10; $tens=$i%100; switch($units) { case 1:$end=($tens==11)?'th':'st';break; case 2:$end=($tens==12)?'th':'nd';break; case 3:$end=($tens==13)?'th':'rd';break; default: $end="th"; } return $i.$end; } /** * smarty function to get revision number */ function smarty_modifier_revision($filename) { global $REVISIONS,$CONF; if (isset($REVISIONS[$filename])) { $url = "http://{$CONF['STATIC_HOST']}".preg_replace('/\.(js|css)$/',".v{$REVISIONS[$filename]}.$1",$filename); if (isset($CONF['curtail_level']) && $CONF['curtail_level'] > 4 && strpos($filename,'css') === FALSE && empty($GLOBALS['USER']->user_id)) { $url = cachize_url($url); } return $url; } else { #return "http://{$CONF['STATIC_HOST']}".preg_replace('/\.(js|css)$/',".v".time().".$1",$filename); return $filename; } } function getSitemapFilepath($level,$square = null,$gr='',$i = 0) { #$i = 270727; if (is_object($square)) { $s = $square->gridsquare; if ($level > 2) { $n = sprintf("%d%d",intval($square->eastings/20)*2,intval($square->northings/20)*2); } if (empty($gr)) { $gr = $square->grid_reference; } } elseif (!empty($gr)) { preg_match('/^([A-Z]{1,3})([\d_]*)([NS]*)([EW]*)$/',strtoupper($gr),$m); $s = $m[1]; if ($level > 2) { $numbers = $m[2]; $numlen = strlen($m[2]); $c = $numlen/2; $n = sprintf("%d%d",intval($numbers{0}/2)*2,intval($numbers{$c}/2)*2); } } if ($level == 5) { //if level 5 quantize to subhectad/mosaic (and define gr to be in SH43NW format) //SH4(0)35 -> SH435(W) $gr = preg_replace('/^(.+)[5-9](\d)(\d)$/','$1$2$3E',$gr); $gr = preg_replace('/^(.+)[0-4](\d)(\d)$/','$1$2$3W',$gr); //SH43(5)E -> SH43(N)E $gr = preg_replace('/^(.+)[5-9]([EW])$/e','$1."N".$2',$gr); $gr = preg_replace('/^(.+)[0-4]([EW])$/e','$1."S".$2',$gr); } $extension = 'html'; $prefix = "/sitemap"; if ($i) { $prefix .= "/$i"; } if ($level == 3) { return "$prefix/$s/$n.$extension"; } elseif ($level == 2) { return "$prefix/$s.$extension"; } elseif ($level == 1) { return "$prefix/geograph.$extension"; } else { return "$prefix/$s/$n/$level/$gr.$extension"; } } /** * smarty wrapper to GeographLinks */ function smarty_function_geographlinks($input,$thumbs = false) { return GeographLinks($input,$thumbs); } //replace geograph links function GeographLinks(&$posterText,$thumbs = false) { global $imageCredits,$CONF; //look for [[gridref_or_photoid]] and [[[gridref_or_photoid]]] if (preg_match_all('/\[\[(\[?)([a-z]+:)?(\w{0,3} ?\d+ ?\d*)(\]?)\]\]/',$posterText,$g_matches)) { $thumb_count = 0; foreach ($g_matches[3] as $g_i => $g_id) { $server = $_SERVER['HTTP_HOST']; $ext = false; $prefix = ''; if ($g_matches[2][$g_i] == 'de:') { $server = 'geo.hlipp.de'; $ext = true; $prefix = 'de:'; } //photo id? if (is_numeric($g_id)) { if ($global_thumb_count > $CONF['global_thumb_limit'] || $thumb_count > $CONF['post_thumb_limit']) { $posterText = preg_replace("/\[?\[\[$prefix$g_id\]\]\]?/","[[$prefix$g_id]]",$posterText); } else { if (!isset($g_image)) { $g_image=new GridImage; } if ($ext) { $ok = $g_image->loadFromServer($server, $g_id); } else { $ok = $g_image->loadFromId($g_id); } if ($g_image->moderation_status == 'rejected') { $posterText = str_replace("[[[$prefix$g_id]]]",'image no longer available',$posterText); } elseif ($ok) { $g_title=$g_image->grid_reference.' : '.htmlentities2($g_image->title); if ($g_matches[1][$g_i]) { if ($thumbs) { $g_title.=' by '.htmlentities($g_image->realname); $g_img = $g_image->getThumbnail(120,120,false,true); $posterText = str_replace("[[[$prefix$g_id]]]","$g_img",$posterText); if (isset($imageCredits[$g_image->realname])) { $imageCredits[$g_image->realname]++; } else { $imageCredits[$g_image->realname]=1; } } else { //we don't place thumbnails in non forum links $posterText = str_replace("[[[$prefix$g_id]]]","$g_title",$posterText); } } else { $posterText = preg_replace("/(?$g_title",$posterText); } } $global_thumb_count++; } $thumb_count++; } else { //link to grid ref $posterText = str_replace("[[$prefix$g_id]]","$g_id",$posterText); } } } if ($CONF['CONTENT_HOST'] != $_SERVER['HTTP_HOST']) { $posterText = str_replace($CONF['CONTENT_HOST'],$_SERVER['HTTP_HOST'],$posterText); } $posterText = preg_replace('/(?F=])(https?:\/\/[\w\.-]+\.\w{2,}\/?[\w\~\-\.\?\,=\'\/\\\+&%\$#\(\)\;\:]*)(?\"\$1\",'text'=>'Link','nofollow'=>1,'title'=>\"\$1\"))",$posterText); $posterText = preg_replace('/(?\"http://\$1\",'text'=>'Link','nofollow'=>1,'title'=>\"\$1\"))",$posterText); return $posterText; } //available as a function, as doesn't come into effect if just re-using a smarty cache function dieUnderHighLoad($threshold = 2,$template = 'function_unavailable.tpl') { global $smarty,$USER,$CONF; if ($threshold == 0) { if ($CONF['template']=='archive') { //heritrix doesn't understand 503 errors - so lets cause it to timeout.... (uses a socket timeout of 20000ms) sleep(30); } header("HTTP/1.1 503 Service Unavailable"); $smarty->assign('searchq',stripslashes($_GET['q'])); $smarty->display($template); exit; } elseif (!isset($_ENV["OS"]) || strpos($_ENV["OS"],'Windows') === FALSE) { $threshold *= 1.5; //lets give registered users a bit more leaway! if ($USER->registered) { $threshold *= 2; } //check load average, abort if too high $buffer = "0 0 0"; if (is_readable("/proc/loadavg")) { $f = fopen("/proc/loadavg","r"); if ($f) { if (!feof($f)) { $buffer = fgets($f, 1024); } fclose($f); } } $loads = explode(" ",$buffer); $load=(float)$loads[0]; if ($load>$threshold) { if ($CONF['template']=='archive') { //heritrix doesn't understand 503 errors - so lets cause it to timeout.... (uses a socket timeout of 20000ms) sleep(30); } header("HTTP/1.1 503 Service Unavailable"); $smarty->assign('searchq',stripslashes($_GET['q'])); $smarty->display($template); exit; } } } function datetimeToTimestamp($datetime) { $p = explode('-',$datetime); return mktime(0, 0, 0, intval($p[1]), intval($p[2]), intval($p[0])); } function getFormattedDate($input) { list($y,$m,$d)=explode('-', $input); $date=""; if ($d>0) { if ($y>1970) { //we can use strftime $t=strtotime($input." 0:0:0");//stop a warning $date=strftime("%A, %e %B, %Y", $t); //%e doesnt work on WINDOWS! (could use %d) } else { //oh my! $t=strtotime("2000-$m-$d"); $date=strftime("%e %B", $t)." $y"; } } elseif ($m>0) { //well, it saves having an array of months... $t=strtotime("2000-$m-01"); if ($y > 0) { $date=strftime("%B", $t)." $y"; } else { $date=strftime("%B", $t); } } elseif ($y>0) { $date=$y; } return $date; } //credit: http://www.php.net/fsockopen function connectToURL($addr, $port, $path, $userpass="", $timeout="30") { $urlHandle = @fsockopen($addr, $port, $errno, $errstr, $timeout); if ($urlHandle) { socket_set_timeout($urlHandle, $timeout); if ($path) { $urlString = "GET $path HTTP/1.0\r\nHost: $addr\r\nUser-Agent: {$_SERVER['HTTP_HOST']}\r\n"; if ($userpass) $urlString .= "Authorization: Basic ".base64_encode("$userpass")."\r\n"; $urlString .= "\r\n"; fputs($urlHandle, $urlString); $response = fgets($urlHandle); if (substr_count($response, "200 OK") > 0) { // Check the status of the link $endHeader = false; // Strip initial header information while ($urlHandle && !$endHeader && !feof($urlHandle)) { if (fgets($urlHandle) == "\r\n") $endHeader = true; } return $urlHandle; // All OK, return the file handle } else if (strlen($response) < 15) { // Cope with wierd non standard responses fclose($urlHandle); return -1; } else { // Cope with a standard error response fclose($urlHandle); return substr($response,9,3); } } return $urlHandle; } else return 0; } function customCacheControl($mtime,$uniqstr,$useifmod = true,$gmdate_mod = 0) { global $encoding; if (isset($encoding) && $encoding != 'none' && $encoding != '') { $uniqstr .= $encoding; } $hash = "\"".md5($mtime.'-'.$uniqstr)."\""; if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) { // check ETag if($_SERVER['HTTP_IF_NONE_MATCH'] == $hash ) { header("HTTP/1.0 304 Not Modified"); header ("Etag: $hash"); header('Content-Length: 0'); exit; } //also check legacy Etag $hash2 = "\"".$mtime.'-'.md5($uniqstr)."\""; if($_SERVER['HTTP_IF_NONE_MATCH'] == $hash2 ) { header("HTTP/1.0 304 Not Modified"); header ("Etag: $hash2"); header('Content-Length: 0'); exit; } } header ("Etag: $hash"); if (!$gmdate_mod) $gmdate_mod = gmdate('D, d M Y H:i:s', $mtime) . ' GMT'; if ($useifmod && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { $if_modified_since = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']); if ($if_modified_since == $gmdate_mod) { header("HTTP/1.0 304 Not Modified"); header('Content-Length: 0'); exit; } } header("Last-Modified: $gmdate_mod"); } function customNoCacheHeader($type = 'nocache',$disable_auto = false) { //none/nocache/private/private_no_expire/public if ($type == 'nocache') { header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); customExpiresHeader(-1); } if ($disable_auto) { //call to disable the auto session one, could then call another here if needbe session_cache_limiter('none'); } } function customExpiresHeader($diff,$public = false,$overwrite = false) { $private = ($public)?'':', private'; if ($diff > 0) { $expires=gmstrftime("%a, %d %b %Y %H:%M:%S GMT", time()+$diff); header("Expires: $expires"); header("Cache-Control: max-age=$diff$private",$overwrite); if ($overwrite) { header("Pragma:"); //sessions by default set this } } else { header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past header("Cache-Control: max-age=0$private",$overwrite); } if ($public) header("Cache-Control: Public",false); } function getEncoding() { global $encoding; if (!empty($_SERVER['HTTP_ACCEPT_ENCODING'])) { $gzip = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip'); $deflate = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate'); $encoding = $gzip ? 'gzip' : ($deflate ? 'deflate' : ''); if (!strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') && preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $matches)) { $version = floatval($matches[1]); if ($version < 6) $encoding = ''; if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'EV1')) $encoding = ''; } } else { $encoding = ''; } return $encoding; } function customGZipHandlerStart() { global $encoding; if ($encoding = getEncoding()) { ob_start(); register_shutdown_function('customGZipHandlerEnd'); } } function customGZipHandlerEnd() { global $encoding; $contents =& ob_get_clean(); if (isset($encoding) && $encoding) { // Send compressed contents $contents = gzencode($contents, 9, ($encoding == 'gzip') ? FORCE_GZIP : FORCE_DEFLATE); header ('Content-Encoding: '.$encoding); header ('Vary: Accept-Encoding'); } //else ... we could still send Vary: but because a browser that doesnt will accept non gzip in all cases, doesnt matter if the cache caches the non compressed version (the otherway doesnt hold true, hence the Vary: above) header('Content-Length: '.strlen($contents)); echo $contents; } function htmlspecialchars2( $myHTML,$quotes = ENT_COMPAT,$char_set = 'ISO-8859-1') { return preg_replace( "/&([A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};|#x[0-9a-fA-F]{2,4};)/", '&$1' ,htmlspecialchars($myHTML,$quotes,$char_set)); } function htmlentities2( $myHTML,$quotes = ENT_COMPAT,$char_set = 'ISO-8859-1') { return preg_replace( "/&([A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};|#x[0-9a-fA-F]{2,4};)/", '&$1' ,htmlentities($myHTML,$quotes,$char_set)); } function htmlnumericentities($myXML){ return str_replace('&amp;','&',preg_replace('/[^!-%\x27-;=?-~ ]/e', '"&#".ord("$0").chr(59)', htmlspecialchars($myXML))); } function pagesString($currentPage,$numberOfPages,$prefix,$postfix = '',$extrahtml = '',$showLastPage = false) { static $r; if (!empty($r)) return($r); if ($currentPage > 1) $r .= "< < prev "; $start = max(1,$currentPage-5); $endr = min($numberOfPages+1,$currentPage+8); if ($start > 1) $r .= "1 ... "; for($index = $start;$index<$endr;$index++) { if ($index == $currentPage) $r .= "$index "; else $r .= "$index "; } if ($endr < $numberOfPages+1) $r .= "... "; if ($numberOfPages > $currentPage) $r .= "next >> "; if ($showLastPage) $r .= "last "; return $r; } /** * returns a standard textual representation of a number */ function heading_string($deg) { $dirs = array('north','east','south','west'); $rounded = round($deg / 22.5) % 16; if ($rounded < 0) $rounded += 16; if (($rounded % 4) == 0) { $s = $dirs[$rounded/4]; } else { $s = $dirs[2 * intval(((intval($rounded / 4) + 1) % 4) / 2)]; $s .= $dirs[1 + 2 * intval($rounded / 8)]; if ($rounded % 2 == 1) { $s = $dirs[round($rounded/4) % 4] . '-' . $s; } } return $s; } ?>