[5341] | 1 | <?php |
---|
| 2 | /** |
---|
| 3 | * Utility functions of a general nature which are used by |
---|
| 4 | * most AWL library classes. |
---|
| 5 | * |
---|
| 6 | * @package awl |
---|
| 7 | * @subpackage Utilities |
---|
| 8 | * @author Andrew McMillan <andrew@mcmillan.net.nz> |
---|
| 9 | * @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/> |
---|
| 10 | * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LGPL version 3 or later |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | if ( !function_exists('dbg_error_log') ) { |
---|
| 14 | /** |
---|
| 15 | * Writes a debug message into the error log using printf syntax. If the first |
---|
| 16 | * parameter is "ERROR" then the message will _always_ be logged. |
---|
| 17 | * Otherwise, the first parameter is a "component" name, and will only be logged |
---|
| 18 | * if $c->dbg["component"] is set to some non-null value. |
---|
| 19 | * |
---|
| 20 | * If you want to see every log message then $c->dbg["ALL"] can be set, to |
---|
| 21 | * override the debugging status of the individual components. |
---|
| 22 | * |
---|
| 23 | * @var string $component The component to identify itself, or "ERROR", or "LOG:component" |
---|
| 24 | * @var string $format A format string for the log message |
---|
| 25 | * @var [string $parameter ...] Parameters for the format string. |
---|
| 26 | */ |
---|
| 27 | function dbg_error_log() { |
---|
| 28 | global $c; |
---|
| 29 | $args = func_get_args(); |
---|
| 30 | $type = "DBG"; |
---|
| 31 | $component = array_shift($args); |
---|
| 32 | if ( substr( $component, 0, 3) == "LOG" ) { |
---|
| 33 | // Special escape case for stuff that always gets logged. |
---|
| 34 | $type = 'LOG'; |
---|
| 35 | $component = substr($component,4); |
---|
| 36 | } |
---|
| 37 | else if ( $component == "ERROR" ) { |
---|
| 38 | $type = "***"; |
---|
| 39 | } |
---|
| 40 | else if ( isset($c->dbg["ALL"]) ) { |
---|
| 41 | $type = "ALL"; |
---|
| 42 | } |
---|
| 43 | else if ( !isset($c->dbg[strtolower($component)]) ) return; |
---|
| 44 | |
---|
| 45 | $argc = func_num_args(); |
---|
| 46 | if ( 2 <= $argc ) { |
---|
| 47 | $format = array_shift($args); |
---|
| 48 | } |
---|
| 49 | else { |
---|
| 50 | $format = "%s"; |
---|
| 51 | } |
---|
| 52 | @error_log( $c->sysabbr.": $type: $component:". vsprintf( $format, $args ) ); |
---|
| 53 | } |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | |
---|
| 57 | if ( !function_exists('fatal') ) { |
---|
| 58 | function fatal() { |
---|
| 59 | global $c; |
---|
| 60 | $args = func_get_args(); |
---|
| 61 | $argc = func_num_args(); |
---|
| 62 | if ( 2 <= $argc ) { |
---|
| 63 | $format = array_shift($args); |
---|
| 64 | } |
---|
| 65 | else { |
---|
| 66 | $format = "%s"; |
---|
| 67 | } |
---|
| 68 | @error_log( $c->sysabbr.": FATAL: $component:". vsprintf( $format, $args ) ); |
---|
| 69 | |
---|
| 70 | @error_log( "================= Stack Trace ===================" ); |
---|
| 71 | |
---|
| 72 | $trace = array_reverse(debug_backtrace()); |
---|
| 73 | array_pop($trace); |
---|
| 74 | foreach( $trace AS $k => $v ) { |
---|
| 75 | @error_log( sprintf(" ===> %s[%d] calls %s%s%s()", |
---|
| 76 | $v['file'], |
---|
| 77 | $v['line'], |
---|
| 78 | (isset($v['class'])?$v['class']:''), |
---|
| 79 | (isset($v['type'])?$v['type']:''), |
---|
| 80 | (isset($v['function'])?$v['function']:'') |
---|
| 81 | )); |
---|
| 82 | } |
---|
| 83 | echo "Fatal Error"; |
---|
| 84 | exit(); |
---|
| 85 | } |
---|
| 86 | } |
---|
| 87 | |
---|
| 88 | |
---|
| 89 | if ( !function_exists('trace_bug') ) { |
---|
| 90 | /** |
---|
| 91 | * Not as sever as a fatal() call, but we want to log and trace it |
---|
| 92 | */ |
---|
| 93 | function trace_bug() { |
---|
| 94 | global $c; |
---|
| 95 | $args = func_get_args(); |
---|
| 96 | $argc = func_num_args(); |
---|
| 97 | if ( 2 <= $argc ) { |
---|
| 98 | $format = array_shift($args); |
---|
| 99 | } |
---|
| 100 | else { |
---|
| 101 | $format = "%s"; |
---|
| 102 | } |
---|
| 103 | @error_log( $c->sysabbr.": BUG: $component:". vsprintf( $format, $args ) ); |
---|
| 104 | |
---|
| 105 | @error_log( "================= Stack Trace ===================" ); |
---|
| 106 | |
---|
| 107 | $trace = array_reverse(debug_backtrace()); |
---|
| 108 | array_pop($trace); |
---|
| 109 | foreach( $trace AS $k => $v ) { |
---|
| 110 | @error_log( sprintf(" ===> %s[%d] calls %s%s%s()", |
---|
| 111 | $v['file'], |
---|
| 112 | $v['line'], |
---|
| 113 | (isset($v['class'])?$v['class']:''), |
---|
| 114 | (isset($v['type'])?$v['type']:''), |
---|
| 115 | (isset($v['function'])?$v['function']:'') |
---|
| 116 | )); |
---|
| 117 | } |
---|
| 118 | } |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | |
---|
| 122 | if ( !function_exists('apache_request_headers') ) { |
---|
| 123 | /** |
---|
| 124 | * Compatibility so we can use the apache function name and still work with CGI |
---|
| 125 | * @package awl |
---|
| 126 | */ |
---|
| 127 | eval(' |
---|
| 128 | function apache_request_headers() { |
---|
| 129 | foreach($_SERVER as $key=>$value) { |
---|
| 130 | if (substr($key,0,5)=="HTTP_") { |
---|
| 131 | $key=str_replace(" ","-",ucwords(strtolower(str_replace("_"," ",substr($key,5))))); |
---|
| 132 | $out[$key]=$value; |
---|
| 133 | } |
---|
| 134 | } |
---|
| 135 | return $out; |
---|
| 136 | } |
---|
| 137 | '); |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | |
---|
| 141 | |
---|
| 142 | if ( !function_exists('dbg_log_array') ) { |
---|
| 143 | /** |
---|
| 144 | * Function to dump an array to the error log, possibly recursively |
---|
| 145 | * |
---|
| 146 | * @var string $component Which component should this log message identify itself from |
---|
| 147 | * @var string $name What name should this array dump identify itself as |
---|
| 148 | * @var array $arr The array to be dumped. |
---|
| 149 | * @var boolean $recursive Should the dump recurse into arrays/objects in the array |
---|
| 150 | */ |
---|
| 151 | function dbg_log_array( $component, $name, $arr, $recursive = false ) { |
---|
| 152 | if ( !isset($arr) || (gettype($arr) != 'array' && gettype($arr) != 'object') ) { |
---|
| 153 | dbg_error_log( $component, "%s: array is not set, or is not an array!", $name); |
---|
| 154 | return; |
---|
| 155 | } |
---|
| 156 | foreach ($arr as $key => $value) { |
---|
| 157 | dbg_error_log( $component, "%s: >>%s<< = >>%s<<", $name, $key, |
---|
| 158 | (gettype($value) == 'array' || gettype($value) == 'object' ? gettype($value) : $value) ); |
---|
| 159 | if ( $recursive && (gettype($value) == 'array' || (gettype($value) == 'object' && "$key" != 'self' && "$key" != 'parent') ) ) { |
---|
| 160 | dbg_log_array( $component, "$name"."[$key]", $value, $recursive ); |
---|
| 161 | } |
---|
| 162 | } |
---|
| 163 | } |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | |
---|
| 167 | |
---|
| 168 | if ( !function_exists("session_simple_md5") ) { |
---|
| 169 | /** |
---|
| 170 | * Make a plain MD5 hash of a string, identifying the type of hash it is |
---|
| 171 | * |
---|
| 172 | * @param string $instr The string to be salted and MD5'd |
---|
| 173 | * @return string The *MD5* and the MD5 of the string |
---|
| 174 | */ |
---|
| 175 | function session_simple_md5( $instr ) { |
---|
| 176 | global $c; |
---|
| 177 | if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making plain MD5: instr=$instr, md5($instr)=".md5($instr) ); |
---|
| 178 | return ( '*MD5*'. md5($instr) ); |
---|
| 179 | } |
---|
| 180 | } |
---|
| 181 | |
---|
| 182 | |
---|
| 183 | |
---|
| 184 | if ( !function_exists("session_salted_md5") ) { |
---|
| 185 | /** |
---|
| 186 | * Make a salted MD5 string, given a string and (possibly) a salt. |
---|
| 187 | * |
---|
| 188 | * If no salt is supplied we will generate a random one. |
---|
| 189 | * |
---|
| 190 | * @param string $instr The string to be salted and MD5'd |
---|
| 191 | * @param string $salt Some salt to sprinkle into the string to be MD5'd so we don't get the same PW always hashing to the same value. |
---|
| 192 | * @return string The salt, a * and the MD5 of the salted string, as in SALT*SALTEDHASH |
---|
| 193 | */ |
---|
| 194 | function session_salted_md5( $instr, $salt = "" ) { |
---|
| 195 | if ( $salt == "" ) $salt = substr( md5(rand(100000,999999)), 2, 8); |
---|
| 196 | global $c; |
---|
| 197 | if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making salted MD5: salt=$salt, instr=$instr, md5($salt$instr)=".md5($salt . $instr) ); |
---|
| 198 | return ( sprintf("*%s*%s", $salt, md5($salt . $instr) ) ); |
---|
| 199 | } |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | |
---|
| 203 | |
---|
| 204 | if ( !function_exists("session_salted_sha1") ) { |
---|
| 205 | /** |
---|
| 206 | * Make a salted SHA1 string, given a string and (possibly) a salt. PHP5 only (although it |
---|
| 207 | * could be made to work on PHP4 (@see http://www.openldap.org/faq/data/cache/347.html). The |
---|
| 208 | * algorithm used here is compatible with OpenLDAP so passwords generated through this function |
---|
| 209 | * should be able to be migrated to OpenLDAP by using the part following the second '*', i.e. |
---|
| 210 | * the '{SSHA}....' part. |
---|
| 211 | * |
---|
| 212 | * If no salt is supplied we will generate a random one. |
---|
| 213 | * |
---|
| 214 | * @param string $instr The string to be salted and SHA1'd |
---|
| 215 | * @param string $salt Some salt to sprinkle into the string to be SHA1'd so we don't get the same PW always hashing to the same value. |
---|
| 216 | * @return string A *, the salt, a * and the SHA1 of the salted string, as in *SALT*SALTEDHASH |
---|
| 217 | */ |
---|
| 218 | function session_salted_sha1( $instr, $salt = "" ) { |
---|
| 219 | if ( $salt == "" ) $salt = substr( str_replace('*','',base64_encode(sha1(rand(100000,9999999),true))), 2, 9); |
---|
| 220 | global $c; |
---|
| 221 | if ( isset($c->dbg['password']) ) dbg_error_log( "Login", "Making salted SHA1: salt=$salt, instr=$instr, encoded($instr$salt)=".base64_encode(sha1($instr . $salt, true).$salt) ); |
---|
| 222 | return ( sprintf("*%s*{SSHA}%s", $salt, base64_encode(sha1($instr.$salt, true) . $salt ) ) ); |
---|
| 223 | } |
---|
| 224 | } |
---|
| 225 | |
---|
| 226 | |
---|
| 227 | if ( !function_exists("session_validate_password") ) { |
---|
| 228 | /** |
---|
| 229 | * Checks what a user entered against the actual password on their account. |
---|
| 230 | * @param string $they_sent What the user entered. |
---|
| 231 | * @param string $we_have What we have in the database as their password. Which may (or may not) be a salted MD5. |
---|
| 232 | * @return boolean Whether or not the users attempt matches what is already on file. |
---|
| 233 | */ |
---|
| 234 | function session_validate_password( $they_sent, $we_have ) { |
---|
| 235 | if ( preg_match('/^\*\*.+$/', $we_have ) ) { |
---|
| 236 | // The "forced" style of "**plaintext" to allow easier admin setting |
---|
| 237 | return ( "**$they_sent" == $we_have ); |
---|
| 238 | } |
---|
| 239 | |
---|
| 240 | if ( preg_match('/^\*(.+)\*{[A-Z]+}.+$/', $we_have, $regs ) ) { |
---|
| 241 | if ( function_exists("session_salted_sha1") ) { |
---|
| 242 | // A nicely salted sha1sum like "*<salt>*{SSHA}<salted_sha1>" |
---|
| 243 | $salt = $regs[1]; |
---|
| 244 | $sha1_sent = session_salted_sha1( $they_sent, $salt ) ; |
---|
| 245 | return ( $sha1_sent == $we_have ); |
---|
| 246 | } |
---|
| 247 | else { |
---|
| 248 | dbg_error_log( "ERROR", "Password is salted SHA-1 but you are using PHP4!" ); |
---|
| 249 | echo <<<EOERRMSG |
---|
| 250 | <html> |
---|
| 251 | <head> |
---|
| 252 | <title>Salted SHA1 Password format not supported with PHP4</title> |
---|
| 253 | </head> |
---|
| 254 | <body> |
---|
| 255 | <h1>Salted SHA1 Password format not supported with PHP4</h1> |
---|
| 256 | <p>At some point you have used PHP5 to set the password for this user and now you are |
---|
| 257 | using PHP4. You will need to assign a new password to this user using PHP4, or ensure |
---|
| 258 | you use PHP5 everywhere (recommended).</p> |
---|
| 259 | <p>AWL has now switched to using salted SHA-1 passwords by preference in a format |
---|
| 260 | compatible with OpenLDAP.</p> |
---|
| 261 | </body> |
---|
| 262 | </html> |
---|
| 263 | EOERRMSG; |
---|
| 264 | exit; |
---|
| 265 | } |
---|
| 266 | } |
---|
| 267 | |
---|
| 268 | if ( preg_match('/^\*MD5\*.+$/', $we_have, $regs ) ) { |
---|
| 269 | // A crappy unsalted md5sum like "*MD5*<md5>" |
---|
| 270 | $md5_sent = session_simple_md5( $they_sent ) ; |
---|
| 271 | return ( $md5_sent == $we_have ); |
---|
| 272 | } |
---|
| 273 | else if ( preg_match('/^\*(.+)\*.+$/', $we_have, $regs ) ) { |
---|
| 274 | // A nicely salted md5sum like "*<salt>*<salted_md5>" |
---|
| 275 | $salt = $regs[1]; |
---|
| 276 | $md5_sent = session_salted_md5( $they_sent, $salt ) ; |
---|
| 277 | return ( $md5_sent == $we_have ); |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | // Anything else is bad |
---|
| 281 | return false; |
---|
| 282 | |
---|
| 283 | } |
---|
| 284 | } |
---|
| 285 | |
---|
| 286 | |
---|
| 287 | |
---|
| 288 | if ( !function_exists("replace_uri_params") ) { |
---|
| 289 | /** |
---|
| 290 | * Given a URL (presumably the current one) and a parameter, replace the value of parameter, |
---|
| 291 | * extending the URL as necessary if the parameter is not already there. |
---|
| 292 | * @param string $uri The URI we will be replacing parameters in. |
---|
| 293 | * @param array $replacements An array of replacement pairs array( "replace_this" => "with this" ) |
---|
| 294 | * @return string The URI with the replacements done. |
---|
| 295 | */ |
---|
| 296 | function replace_uri_params( $uri, $replacements ) { |
---|
| 297 | $replaced = $uri; |
---|
| 298 | foreach( $replacements AS $param => $new_value ) { |
---|
| 299 | $rxp = preg_replace( '/([\[\]])/', '\\\\$1', $param ); // Some parameters may be arrays. |
---|
| 300 | $regex = "/([&?])($rxp)=([^&]+)/"; |
---|
| 301 | dbg_error_log("core", "Looking for [%s] to replace with [%s] regex is %s and searching [%s]", $param, $new_value, $regex, $replaced ); |
---|
| 302 | if ( preg_match( $regex, $replaced ) ) |
---|
| 303 | $replaced = preg_replace( $regex, "\$1$param=$new_value", $replaced); |
---|
| 304 | else |
---|
| 305 | $replaced .= "&$param=$new_value"; |
---|
| 306 | } |
---|
| 307 | if ( ! preg_match( '/\?/', $replaced ) ) { |
---|
| 308 | $replaced = preg_replace("/&(.+)$/", "?\$1", $replaced); |
---|
| 309 | } |
---|
| 310 | $replaced = str_replace("&", "--AmPeRsAnD--", $replaced); |
---|
| 311 | $replaced = str_replace("&", "&", $replaced); |
---|
| 312 | $replaced = str_replace("--AmPeRsAnD--", "&", $replaced); |
---|
| 313 | dbg_error_log("core", "URI <<$uri>> morphed to <<$replaced>>"); |
---|
| 314 | return $replaced; |
---|
| 315 | } |
---|
| 316 | } |
---|
| 317 | |
---|
| 318 | |
---|
| 319 | if ( !function_exists("uuid") ) { |
---|
| 320 | /** |
---|
| 321 | * Generates a Universally Unique IDentifier, version 4. |
---|
| 322 | * |
---|
| 323 | * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally |
---|
| 324 | * Unique IDentifiers (GUID), as well as several methods for producing them. One |
---|
| 325 | * such method, described in section 4.4, is based on truly random or pseudo-random |
---|
| 326 | * number generators, and is therefore implementable in a language like PHP. |
---|
| 327 | * |
---|
| 328 | * We choose to produce pseudo-random numbers with the Mersenne Twister, and to always |
---|
| 329 | * limit single generated numbers to 16 bits (ie. the decimal value 65535). That is |
---|
| 330 | * because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed* |
---|
| 331 | * value, with only the equivalent of 31 significant bits. Producing two 16-bit random |
---|
| 332 | * numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits |
---|
| 333 | * are random. |
---|
| 334 | * |
---|
| 335 | * The algorithm for version 4 UUIDs (ie. those based on random number generators) |
---|
| 336 | * states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits, |
---|
| 337 | * 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should |
---|
| 338 | * be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should |
---|
| 339 | * be 01. We try to conform to that definition as efficiently as possible, generating |
---|
| 340 | * smaller values where possible, and minimizing the number of base conversions. |
---|
| 341 | * |
---|
| 342 | * @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for |
---|
| 343 | * any purpose ; it is distributed without any form of warranty whatsoever. |
---|
| 344 | * @author David Holmes <dholmes@cfdsoftware.net> |
---|
| 345 | * |
---|
| 346 | * @return string A UUID, made up of 32 hex digits and 4 hyphens. |
---|
| 347 | */ |
---|
| 348 | |
---|
| 349 | function uuid() { |
---|
| 350 | |
---|
| 351 | // The field names refer to RFC 4122 section 4.1.2 |
---|
| 352 | |
---|
| 353 | return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x', |
---|
| 354 | mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low" |
---|
| 355 | mt_rand(0, 65535), // 16 bits for "time_mid" |
---|
| 356 | mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version" |
---|
| 357 | bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)), |
---|
| 358 | // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res" |
---|
| 359 | // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d) |
---|
| 360 | // 8 bits for "clk_seq_low" |
---|
| 361 | mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node" |
---|
| 362 | ); |
---|
| 363 | } |
---|
| 364 | } |
---|
| 365 | |
---|
| 366 | if ( !function_exists("translate") ) { |
---|
[5399] | 367 | require_once ROOTPATH.'/plugins/davicalCliente/Translation.php'; |
---|
[5341] | 368 | |
---|
| 369 | } |
---|
| 370 | |
---|
| 371 | if ( !function_exists("clone") && version_compare(phpversion(), '5.0') < 0) { |
---|
| 372 | /** |
---|
| 373 | * PHP5 screws with the assignment operator changing so that $a = $b means that |
---|
| 374 | * $a becomes a reference to $b. There is a clone() that we can use in PHP5, so |
---|
| 375 | * we have to emulate that for PHP4. Bleargh. |
---|
| 376 | */ |
---|
| 377 | eval( 'function clone($object) { return $object; }' ); |
---|
| 378 | } |
---|
| 379 | |
---|
| 380 | if ( !function_exists("quoted_printable_encode") ) { |
---|
| 381 | /** |
---|
| 382 | * Process a string to fit the requirements of RFC2045 section 6.7. Note that |
---|
| 383 | * this works, but replaces more characters than the minimum set. For readability |
---|
| 384 | * the spaces aren't encoded as =20 though. |
---|
| 385 | */ |
---|
| 386 | function quoted_printable_encode($string) { |
---|
| 387 | return preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n", str_replace("%","=",str_replace("%20"," ",rawurlencode($string)))); |
---|
| 388 | } |
---|
| 389 | } |
---|
| 390 | |
---|
| 391 | |
---|
| 392 | if ( !function_exists("check_by_regex") ) { |
---|
| 393 | /** |
---|
| 394 | * Verify a value is OK by testing a regex against it. If it is an array apply it to |
---|
| 395 | * each element in the array recursively. If it is an object we don't mess |
---|
| 396 | * with it. |
---|
| 397 | */ |
---|
| 398 | function check_by_regex( $val, $regex ) { |
---|
| 399 | if ( is_null($val) ) return null; |
---|
| 400 | switch( $regex ) { |
---|
| 401 | case 'int': $regex = '#^\d+$#'; break; |
---|
| 402 | } |
---|
| 403 | if ( is_array($val) ) { |
---|
| 404 | foreach( $val AS $k => $v ) { |
---|
| 405 | $val[$k] = check_by_regex($v,$regex); |
---|
| 406 | } |
---|
| 407 | } |
---|
| 408 | else if ( ! is_object($val) ) { |
---|
| 409 | if ( preg_match( $regex, $val, $matches) ) { |
---|
| 410 | $val = $matches[0]; |
---|
| 411 | } |
---|
| 412 | else { |
---|
| 413 | $val = ''; |
---|
| 414 | } |
---|
| 415 | } |
---|
| 416 | return $val; |
---|
| 417 | } |
---|
| 418 | } |
---|
| 419 | |
---|
| 420 | |
---|
| 421 | if ( !function_exists("param_to_global") ) { |
---|
| 422 | /** |
---|
| 423 | * Convert a parameter to a global. We first look in _POST and then in _GET, |
---|
| 424 | * and if they passed in a bunch of valid characters, we will make sure the |
---|
| 425 | * incoming is cleaned to only match that set. |
---|
| 426 | * |
---|
| 427 | * @param string $varname The name of the global variable to put the answer in |
---|
| 428 | * @param string $match_regex The part of the parameter matching this regex will be returned |
---|
| 429 | * @param string $alias1 An alias for the name that we should look for first. |
---|
| 430 | * @param " ... More aliases, in the order which they should be examined. $varname will be appended to the end. |
---|
| 431 | */ |
---|
| 432 | function param_to_global( ) { |
---|
| 433 | $args = func_get_args(); |
---|
| 434 | |
---|
| 435 | $varname = array_shift($args); |
---|
| 436 | $GLOBALS[$varname] = null; |
---|
| 437 | |
---|
| 438 | $match_regex = null; |
---|
| 439 | $argc = func_num_args(); |
---|
| 440 | if ( $argc > 1 ) { |
---|
| 441 | $match_regex = array_shift($args); |
---|
| 442 | } |
---|
| 443 | |
---|
| 444 | $args[] = $varname; |
---|
| 445 | foreach( $args AS $k => $name ) { |
---|
| 446 | if ( isset($_POST[$name]) ) { |
---|
| 447 | $result = $_POST[$name]; |
---|
| 448 | break; |
---|
| 449 | } |
---|
| 450 | else if ( isset($_GET[$name]) ) { |
---|
| 451 | $result = $_GET[$name]; |
---|
| 452 | break; |
---|
| 453 | } |
---|
| 454 | } |
---|
| 455 | if ( !isset($result) ) return null; |
---|
| 456 | |
---|
| 457 | if ( isset($match_regex) ) { |
---|
| 458 | $result = check_by_regex( $result, $match_regex ); |
---|
| 459 | } |
---|
| 460 | |
---|
| 461 | $GLOBALS[$varname] = $result; |
---|
| 462 | return $result; |
---|
| 463 | } |
---|
| 464 | } |
---|
| 465 | |
---|
| 466 | |
---|
| 467 | if ( !function_exists("get_fields") ) { |
---|
| 468 | /** |
---|
| 469 | * @var array $_AWL_field_cache is a cache of the field names for a table |
---|
| 470 | */ |
---|
| 471 | $_AWL_field_cache = array(); |
---|
| 472 | |
---|
| 473 | /** |
---|
| 474 | * Get the names of the fields for a particular table |
---|
| 475 | * @param string $tablename The name of the table. |
---|
| 476 | * @return array of string The public fields in the table. |
---|
| 477 | */ |
---|
| 478 | function get_fields( $tablename ) { |
---|
| 479 | global $_AWL_field_cache; |
---|
| 480 | |
---|
| 481 | if ( !isset($_AWL_field_cache[$tablename]) ) { |
---|
| 482 | dbg_error_log( "core", ":get_fields: Loading fields for table '$tablename'" ); |
---|
| 483 | $qry = new AwlQuery(); |
---|
| 484 | $db = $qry->GetConnection(); |
---|
| 485 | $qry->SetSQL($db->GetFields($tablename)); |
---|
| 486 | $qry->Exec("core"); |
---|
| 487 | $fields = array(); |
---|
| 488 | while( $row = $qry->Fetch() ) { |
---|
| 489 | $fields[$row->fieldname] = $row->typename . ($row->precision >= 0 ? sprintf('(%d)',$row->precision) : ''); |
---|
| 490 | } |
---|
| 491 | $_AWL_field_cache[$tablename] = $fields; |
---|
| 492 | } |
---|
| 493 | return $_AWL_field_cache[$tablename]; |
---|
| 494 | } |
---|
| 495 | } |
---|
| 496 | |
---|
| 497 | |
---|
| 498 | if ( !function_exists("force_utf8") ) { |
---|
| 499 | function define_byte_mappings() { |
---|
| 500 | global $byte_map, $nibble_good_chars; |
---|
| 501 | |
---|
| 502 | # Needed for using Grant McLean's byte mappings code |
---|
| 503 | $ascii_char = '[\x00-\x7F]'; |
---|
| 504 | $cont_byte = '[\x80-\xBF]'; |
---|
| 505 | |
---|
| 506 | $utf8_2 = '[\xC0-\xDF]' . $cont_byte; |
---|
| 507 | $utf8_3 = '[\xE0-\xEF]' . $cont_byte . '{2}'; |
---|
| 508 | $utf8_4 = '[\xF0-\xF7]' . $cont_byte . '{3}'; |
---|
| 509 | $utf8_5 = '[\xF8-\xFB]' . $cont_byte . '{4}'; |
---|
| 510 | |
---|
| 511 | $nibble_good_chars = "/^($ascii_char+|$utf8_2|$utf8_3|$utf8_4|$utf8_5)(.*)$/s"; |
---|
| 512 | |
---|
| 513 | # From http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT |
---|
| 514 | $byte_map = array( |
---|
| 515 | "\x80" => "\xE2\x82\xAC", # EURO SIGN |
---|
| 516 | "\x82" => "\xE2\x80\x9A", # SINGLE LOW-9 QUOTATION MARK |
---|
| 517 | "\x83" => "\xC6\x92", # LATIN SMALL LETTER F WITH HOOK |
---|
| 518 | "\x84" => "\xE2\x80\x9E", # DOUBLE LOW-9 QUOTATION MARK |
---|
| 519 | "\x85" => "\xE2\x80\xA6", # HORIZONTAL ELLIPSIS |
---|
| 520 | "\x86" => "\xE2\x80\xA0", # DAGGER |
---|
| 521 | "\x87" => "\xE2\x80\xA1", # DOUBLE DAGGER |
---|
| 522 | "\x88" => "\xCB\x86", # MODIFIER LETTER CIRCUMFLEX ACCENT |
---|
| 523 | "\x89" => "\xE2\x80\xB0", # PER MILLE SIGN |
---|
| 524 | "\x8A" => "\xC5\xA0", # LATIN CAPITAL LETTER S WITH CARON |
---|
| 525 | "\x8B" => "\xE2\x80\xB9", # SINGLE LEFT-POINTING ANGLE QUOTATION MARK |
---|
| 526 | "\x8C" => "\xC5\x92", # LATIN CAPITAL LIGATURE OE |
---|
| 527 | "\x8E" => "\xC5\xBD", # LATIN CAPITAL LETTER Z WITH CARON |
---|
| 528 | "\x91" => "\xE2\x80\x98", # LEFT SINGLE QUOTATION MARK |
---|
| 529 | "\x92" => "\xE2\x80\x99", # RIGHT SINGLE QUOTATION MARK |
---|
| 530 | "\x93" => "\xE2\x80\x9C", # LEFT DOUBLE QUOTATION MARK |
---|
| 531 | "\x94" => "\xE2\x80\x9D", # RIGHT DOUBLE QUOTATION MARK |
---|
| 532 | "\x95" => "\xE2\x80\xA2", # BULLET |
---|
| 533 | "\x96" => "\xE2\x80\x93", # EN DASH |
---|
| 534 | "\x97" => "\xE2\x80\x94", # EM DASH |
---|
| 535 | "\x98" => "\xCB\x9C", # SMALL TILDE |
---|
| 536 | "\x99" => "\xE2\x84\xA2", # TRADE MARK SIGN |
---|
| 537 | "\x9A" => "\xC5\xA1", # LATIN SMALL LETTER S WITH CARON |
---|
| 538 | "\x9B" => "\xE2\x80\xBA", # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK |
---|
| 539 | "\x9C" => "\xC5\x93", # LATIN SMALL LIGATURE OE |
---|
| 540 | "\x9E" => "\xC5\xBE", # LATIN SMALL LETTER Z WITH CARON |
---|
| 541 | "\x9F" => "\xC5\xB8", # LATIN CAPITAL LETTER Y WITH DIAERESIS |
---|
| 542 | ); |
---|
| 543 | |
---|
| 544 | for( $i=160; $i < 256; $i++ ) { |
---|
| 545 | $ch = chr($i); |
---|
| 546 | $byte_map[$ch] = iconv('ISO-8859-1', 'UTF-8', $ch); |
---|
| 547 | } |
---|
| 548 | } |
---|
| 549 | define_byte_mappings(); |
---|
| 550 | |
---|
| 551 | function force_utf8( $input ) { |
---|
| 552 | global $byte_map, $nibble_good_chars; |
---|
| 553 | |
---|
| 554 | $output = ''; |
---|
| 555 | $char = ''; |
---|
| 556 | $rest = ''; |
---|
| 557 | while( $input != '' ) { |
---|
| 558 | if ( preg_match( $nibble_good_chars, $input, $matches ) ) { |
---|
| 559 | $output .= $matches[1]; |
---|
| 560 | $rest = $matches[2]; |
---|
| 561 | } |
---|
| 562 | else { |
---|
| 563 | preg_match( '/^(.)(.*)$/s', $input, $matches ); |
---|
| 564 | $char = $matches[1]; |
---|
| 565 | $rest = $matches[2]; |
---|
| 566 | if ( isset($byte_map[$char]) ) { |
---|
| 567 | $output .= $byte_map[$char]; |
---|
| 568 | } |
---|
| 569 | else { |
---|
| 570 | # Must be valid UTF8 already |
---|
| 571 | $output .= $char; |
---|
| 572 | } |
---|
| 573 | } |
---|
| 574 | $input = $rest; |
---|
| 575 | } |
---|
| 576 | return $output; |
---|
| 577 | } |
---|
| 578 | |
---|
| 579 | } |
---|
| 580 | |
---|
| 581 | |
---|
| 582 | /** |
---|
| 583 | * Try and extract something like "Pacific/Auckland" or "America/Indiana/Indianapolis" if possible. |
---|
| 584 | */ |
---|
| 585 | function olson_from_tzstring( $tzstring ) { |
---|
| 586 | global $c; |
---|
| 587 | |
---|
| 588 | if ( function_exists('timezone_identifiers_list') && in_array($tzstring,timezone_identifiers_list()) ) return $tzstring; |
---|
| 589 | if ( preg_match( '{((Antarctica|America|Africa|Atlantic|Asia|Australia|Indian|Europe|Pacific)/(([^/]+)/)?[^/]+)$}', $tzstring, $matches ) ) { |
---|
| 590 | // dbg_error_log( 'INFO', 'Found timezone "%s" from string "%s"', $matches[1], $tzstring ); |
---|
| 591 | return $matches[1]; |
---|
| 592 | } |
---|
| 593 | switch( $tzstring ) { |
---|
| 594 | case 'New Zealand Standard Time': case 'New Zealand Daylight Time': |
---|
| 595 | return 'Pacific/Auckland'; |
---|
| 596 | break; |
---|
| 597 | case 'Central Standard Time': case 'Central Daylight Time': case 'US/Central': |
---|
| 598 | return 'America/Chicago'; |
---|
| 599 | break; |
---|
| 600 | case 'Eastern Standard Time': case 'Eastern Daylight Time': case 'US/Eastern': |
---|
| 601 | case '(UTC-05:00) Eastern Time (US & Canada)': |
---|
| 602 | return 'America/New_York'; |
---|
| 603 | break; |
---|
| 604 | case 'Pacific Standard Time': case 'Pacific Daylight Time': case 'US/Pacific': |
---|
| 605 | return 'America/Los_Angeles'; |
---|
| 606 | break; |
---|
| 607 | case 'Mountain Standard Time': case 'Mountain Daylight Time': case 'US/Mountain': case 'Mountain Time': |
---|
| 608 | return 'America/Denver'; |
---|
| 609 | // The US 'Mountain Time' can in fact be America/(Denver|Boise|Phoenix|Shiprock) which |
---|
| 610 | // all vary to some extent due to differing DST rules. |
---|
| 611 | break; |
---|
| 612 | case '(GMT-07.00) Arizona': |
---|
| 613 | return 'America/Phoenix'; |
---|
| 614 | break; |
---|
| 615 | default: |
---|
| 616 | if ( isset($c->timezone_translations) && is_array($c->timezone_translations) |
---|
| 617 | && !empty($c->timezone_translations[$tzstring]) ) |
---|
| 618 | return $c->timezone_translations[$tzstring]; |
---|
| 619 | } |
---|
| 620 | return null; |
---|
| 621 | } |
---|
| 622 | |
---|
| 623 | if ( !function_exists("deprecated") ) { |
---|
| 624 | function deprecated( $method ) { |
---|
| 625 | global $c; |
---|
| 626 | if ( isset($c->dbg['ALL']) || isset($c->dbg['deprecated']) ) { |
---|
| 627 | $stack = debug_backtrace(); |
---|
| 628 | array_shift($stack); |
---|
| 629 | if ( preg_match( '{/inc/iCalendar.php$}', $stack[0]['file'] ) && $stack[0]['line'] > __LINE__ ) return; |
---|
| 630 | @error_log( sprintf( $c->sysabbr.':DEPRECATED: Call to deprecated method "%s"', $method)); |
---|
| 631 | foreach( $stack AS $k => $v ) { |
---|
| 632 | @error_log( sprintf( $c->sysabbr.': ==> called from line %4d of %s', $v['line'], $v['file'])); |
---|
| 633 | } |
---|
| 634 | } |
---|
| 635 | } |
---|
| 636 | } |
---|
| 637 | |
---|
| 638 | |
---|
| 639 | if ( !function_exists("gzdecode") ) { |
---|
| 640 | function gzdecode( $instring ) { |
---|
| 641 | global $c; |
---|
| 642 | if ( !isset($c->use_pipe_gunzip) || $c->use_pipe_gunzip ) { |
---|
| 643 | $descriptorspec = array( |
---|
| 644 | 0 => array("pipe", "r"), // stdin is a pipe that the child will read from |
---|
| 645 | 1 => array("pipe", "w"), // stdout is a pipe that the child will write to |
---|
| 646 | 2 => array("file", "/dev/null", "a") // stderr is discarded |
---|
| 647 | ); |
---|
| 648 | $process = proc_open('gunzip',$descriptorspec, $pipes); |
---|
| 649 | if ( is_resource($process) ) { |
---|
| 650 | fwrite($pipes[0],$instring); |
---|
| 651 | fclose($pipes[0]); |
---|
| 652 | |
---|
| 653 | $outstring = stream_get_contents($pipes[1]); |
---|
| 654 | fclose($pipes[1]); |
---|
| 655 | |
---|
| 656 | proc_close($process); |
---|
| 657 | return $outstring; |
---|
| 658 | } |
---|
| 659 | return ''; |
---|
| 660 | } |
---|
| 661 | else { |
---|
| 662 | $g=tempnam('./','gz'); |
---|
| 663 | file_put_contents($g,$instring); |
---|
| 664 | ob_start(); |
---|
| 665 | readgzfile($g); |
---|
| 666 | $d=ob_get_clean(); |
---|
| 667 | unlink($g); |
---|
| 668 | return $d; |
---|
| 669 | } |
---|
| 670 | } |
---|
| 671 | } |
---|
| 672 | |
---|
| 673 | /** |
---|
| 674 | * Return the AWL version |
---|
| 675 | */ |
---|
| 676 | function awl_version() { |
---|
| 677 | global $c; |
---|
| 678 | $c->awl_library_version = 0.49; |
---|
| 679 | return $c->awl_library_version; |
---|
| 680 | } |
---|