PageRenderTime 156ms CodeModel.GetById 41ms RepoModel.GetById 1ms app.codeStats 0ms

/doc/forum/proxy/includes/init.php

https://code.google.com/p/fullmetalgalaxy/
PHP | 976 lines | 386 code | 297 blank | 293 comment | 120 complexity | d018c18fa5f3069589d5259ed4ccfcec MD5 | raw file
Possible License(s): AGPL-3.0, GPL-3.0, Apache-2.0, CC-BY-3.0
  1. <?php
  2. /*******************************************************************
  3. * Glype Proxy Script
  4. *
  5. * Copyright (c) 2008, http://www.glype.com/
  6. *
  7. * Permission to use this script is granted free of charge
  8. * subject to the terms displayed at http://www.glype.com/downloads
  9. * and in the LICENSE.txt document of the glype package.
  10. *******************************************************************
  11. * This file is a global include used everywhere in the script.
  12. * Obviously we have all the globally used code: functions and built-in
  13. * "configurable" values. Ideally keep it as light as possible!
  14. ******************************************************************/
  15. /*****************************************************************
  16. * Initialise
  17. ******************************************************************/
  18. // Choose error reporting levels
  19. error_reporting(E_ALL);
  20. ini_set('display_errors', 0); // Always report but don't display on live installation
  21. // Script name (change this if you rename browse.php)
  22. define('SCRIPT_NAME', 'browse.php');
  23. // Prefix for cookies (change if having trouble running multiple proxies on same domain)
  24. define('COOKIE_PREFIX', 'c');
  25. // Running on HTTPS?
  26. define('HTTPS', ( empty($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off' ? false : true ));
  27. // Running in safe_mode?
  28. define('SAFE_MODE', ini_get('safe_mode'));
  29. // Compatibility mode - you can disable this to test if your setup is forwards compatible.
  30. // Backwards compatiblity is frequently removed so keep up to date! Checking this is
  31. // ESSENTIAL if you're distributing a theme or plugin.
  32. define('COMPATABILITY_MODE', true);
  33. // Set up paths/urls
  34. define('GLYPE_ROOT', str_replace('\\', '/', dirname(dirname(__FILE__))));
  35. define('GLYPE_URL',
  36. 'http'
  37. . ( HTTPS ? 's' : '' )
  38. . '://'
  39. . $_SERVER['HTTP_HOST']
  40. . preg_replace('#/(?:(?:includes/)?[^/]*|' . preg_quote(SCRIPT_NAME) . '.*)$#', '', $_SERVER['PHP_SELF'])
  41. );
  42. define('GLYPE_BROWSE', GLYPE_URL . '/' . SCRIPT_NAME);
  43. // Set timezone (uncomment and set to desired timezone)
  44. #date_default_timezone_set('GMT');
  45. // Ensure request time is available
  46. $_SERVER['REQUEST_TIME'] = time();
  47. // Load settings
  48. require GLYPE_ROOT . '/includes/settings.php';
  49. /*****************************************************************
  50. * Language - text for error messages
  51. ******************************************************************/
  52. $phrases['no_hotlink'] = 'Hotlinking directly to proxified pages is not permitted.';
  53. $phrases['unique_mismatch'] = 'The unique URL requested did not match your stored unique salt - this URL was not generated for you or has expired.';
  54. $phrases['invalid_url'] = 'The requested URL was not recognised as a valid URL. Attempted to load: %s';
  55. $phrases['banned_site'] = 'Sorry, this proxy does not allow the requested site (<b>%s</b>) to be viewed.';
  56. $phrases['file_too_large'] = 'The requested file is too large. The maximum permitted filesize is %s MB.';
  57. $phrases['server_busy'] = 'The server is currently busy and unable to process your request. Please try again in a few minutes. We apologise for any inconvenience.';
  58. $phrases['http_error'] = 'The requested resource could not be loaded because the server returned an error:<br> &nbsp; <b>%s %s</b> (<span class="tooltip" onmouseout="exit()" onmouseover="tooltip(\'%s\');">?</span>).';
  59. $phrases['curl_error'] = 'The requested resource could not be loaded. libcurl returned the error:<br><b>%s</b>';
  60. $phrases['unknown_error'] = 'The script encountered an unknown error. Error id: <b>%s</b>.';
  61. // If an HTTP error (status code >= 400) is encountered, the script will look here
  62. // for an additional "friendly" explanation of the problem.
  63. $httpErrors = array('404' => 'A 404 error occurs when the requested resource does not exist.');
  64. /*****************************************************************
  65. * Load theme config
  66. ******************************************************************/
  67. // Current version - no need to change this!
  68. $themeReplace['version'] = 'v1.1';
  69. // Look for a config.php in the /themes/themeName/ folder
  70. if ( ! defined('MULTIGLYPE') && file_exists($tmp = GLYPE_ROOT . '/themes/' . $CONFIG['theme'] . '/config.php') ) {
  71. // Load it
  72. include $tmp;
  73. }
  74. // NB if running multiple proxies off the same source files - with glype
  75. // manager or any other product - set the MULTIGLYPE constant to stop the
  76. // script automatically loading theme config files.
  77. /*****************************************************************
  78. * Start session
  79. ******************************************************************/
  80. // Set name to the configured value - change if running multiple proxies in same
  81. // folder and experiencing session conflicts.
  82. session_name('s');
  83. // Allow caching. We don't want PHP to send any cache-related headers automatically
  84. // (and by default it tries to stop all caching). Using this limiter sends the fewest
  85. // headers, which we override later.
  86. session_cache_limiter('private_no_expire');
  87. // Don't call _start() if session.auto_start = 1
  88. if ( session_id() == '' ) {
  89. session_start();
  90. }
  91. /*****************************************************************
  92. * Check IP bans
  93. ******************************************************************/
  94. // Only check once per session or if the IP address changes
  95. if ( empty($_SESSION['ip_verified']) || $_SESSION['ip_verified'] != $_SERVER['REMOTE_ADDR'] ) {
  96. // Current IP matches a banned IP? true/false
  97. $banned = false;
  98. // Examine all IP bans
  99. foreach ( $CONFIG['ip_bans'] as $ip ) {
  100. // Is this a range or single?
  101. if ( ($pos = strspn($ip, '0123456789.')) == strlen($ip) ) {
  102. // Just a single IP so check for a match
  103. if ( $_SERVER['REMOTE_ADDR'] == $ip ) {
  104. // Flag the match and break out the loop
  105. $banned = true;
  106. break;
  107. }
  108. // And try next IP
  109. continue;
  110. }
  111. // Must be some form of IP range if still here. Convert our own
  112. // IP address to int and binary.
  113. $ownLong = ip2long($_SERVER['REMOTE_ADDR']);
  114. $ownBin = decbin($ownLong);
  115. // What kind of range?
  116. if ( $ip[$pos] == '/' ) {
  117. // Slash notation - split by slash
  118. list($net, $mask) = explode('/', $ip);
  119. // Fill IP with .0 if shortened form
  120. if ( ( $tmp = substr_count($net, '.') ) < 3 ) {
  121. $net .= str_repeat('.0', 3-$tmp);
  122. }
  123. // Note: there MUST be a better way of doing the rest of this section
  124. // but couldn't understand and/or get anything else to work...
  125. // To do: improve!
  126. // Convert a subnet mask to a prefix length
  127. if ( strpos($mask, '.') ) {
  128. $mask = substr_count(decbin(ip2long($mask)), '1');
  129. }
  130. // Produce a binary string of the network address of prefix length
  131. // and compare to the equivalent for own address
  132. if ( substr(decbin(ip2long($net)), 0, $mask) === substr($ownBin, 0, $mask) ) {
  133. // They match so must be banned
  134. $banned = true;
  135. break;
  136. }
  137. } else {
  138. // No slash so it should just be a pair of dotted quads
  139. $from = ip2long(substr($ip, 0, $pos));
  140. $to = ip2long(substr($ip, $pos+1));
  141. // Did we get valid ranges?
  142. if ( $from && $to ) {
  143. // Are we in the range?
  144. if ( $ownLong >= $from && $ownLong <= $to ) {
  145. // We're banned. Don't bother checking the rest of the bans.
  146. $banned = true;
  147. break;
  148. }
  149. }
  150. }
  151. }
  152. // Is the IP address banned?
  153. if ( $banned ) {
  154. // Send a Forbidden header
  155. header('HTTP/1.1 403 Forbidden', true, 403);
  156. // Print the banned page and exit!
  157. echo loadTemplate('banned.page');
  158. exit;
  159. }
  160. // Still here? Must be OK so save IP in session to prevent rechecking next time
  161. $_SESSION['ip_verified'] = $_SERVER['REMOTE_ADDR'];
  162. }
  163. /*****************************************************************
  164. * Find bitfield to determine options from
  165. ******************************************************************/
  166. // First, find the bitfield!
  167. if ( $CONFIG['path_info_urls'] && ! empty($_SERVER['PATH_INFO']) && preg_match('#/b([0-9]{1,5})(?:/f([a-z]{1,10}))?/?$#', $_SERVER['PATH_INFO'], $tmp) ) {
  168. // Found a /bXX/ value at end of path info
  169. $bitfield = $tmp[1];
  170. // (And while we're here, grab the flag too)
  171. $flag = isset($tmp[2]) ? $tmp[2] : '';
  172. } else if ( ! empty($_GET['b']) ) {
  173. // Found a b= value in the query string
  174. $bitfield = intval($_GET['b']);
  175. } else if ( ! empty($_SESSION['bitfield']) ) {
  176. // Use stored session bitfield - mid-browsing but somehow lost the bitfield
  177. $bitfield = $_SESSION['bitfield'];
  178. } else {
  179. // Could not find any bitfield, regenerate (later)
  180. $regenerate = true;
  181. $bitfield = 0;
  182. }
  183. // Get flag from query string while we're here
  184. if ( ! isset($flag) ) {
  185. $flag = isset($_GET['f']) ? $_GET['f'] : '';
  186. }
  187. /*****************************************************************
  188. * Determine options / use defaults
  189. ******************************************************************/
  190. $i = 0;
  191. // Loop through the possible options
  192. foreach ( $CONFIG['options'] as $name => $details ) {
  193. // Is the option forced?
  194. if ( ! empty($details['force']) ) {
  195. // Use default
  196. $options[$name] = $details['default'];
  197. // And move onto next option
  198. continue;
  199. }
  200. // Which bit does this option occupy in the bitfield?
  201. $bit = pow(2, $i);
  202. // Use value from bitfield if possible,
  203. if ( ! isset($regenerate) ) {
  204. // Use value from bitfield
  205. $options[$name] = checkBit($bitfield, $bit);
  206. }
  207. // No bitfield available - use defaults and regenerate
  208. else {
  209. // Use default value
  210. $options[$name] = $details['default'];
  211. // Set bit
  212. if ( $details['default'] ) {
  213. setBit($bitfield, $bit);
  214. }
  215. }
  216. // Increase index
  217. ++$i;
  218. }
  219. // Save new session value
  220. $_SESSION['bitfield'] = $bitfield;
  221. /*****************************************************************
  222. * Unique URLs
  223. ******************************************************************/
  224. if ( $CONFIG['unique_urls'] ) {
  225. // First visit? Ensure we have a unique salt
  226. if ( ! isset($_SESSION['unique_salt']) ) {
  227. // Generate random string
  228. $_SESSION['unique_salt'] = substr(md5(uniqid(true)),rand(0,10),rand(11,20));
  229. }
  230. // Session gets closed before all parsing complete so copy unique to globals
  231. $GLOBALS['unique_salt'] = $_SESSION['unique_salt'];
  232. }
  233. /*****************************************************************
  234. * Sort javascript flags
  235. * These determine how much parsing we do server-side and what can
  236. * be left for the browser client-side.
  237. * FALSE - unknown capabilities, parse all non-standard code
  238. * NULL - javascript override disabled, parse everything
  239. * (array) - flags of which overrides have failed (so parse these)
  240. ******************************************************************/
  241. if ( $CONFIG['override_javascript'] ) {
  242. $jsFlags = isset($_SESSION['js_flags']) ? $_SESSION['js_flags'] : false;
  243. } else {
  244. $jsFlags = null;
  245. }
  246. /*****************************************************************
  247. * Custom browser - set up defaults
  248. ******************************************************************/
  249. if ( ! isset($_SESSION['custom_browser']) ) {
  250. $_SESSION['custom_browser'] = array(
  251. 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
  252. 'referrer' => 'real',
  253. 'tunnel' => '',
  254. 'tunnel_port' => '',
  255. 'tunnel_type' => '',
  256. );
  257. }
  258. /*****************************************************************
  259. * Global functions
  260. * NB: Some of these (e.g. templating) could make up a whole new class
  261. * that could be easily swapped out to completely change how it works.
  262. * In the interests of speed - but at the cost of convenience - all this
  263. * is stuck together in here as functions.
  264. ******************************************************************/
  265. /*****************************************************************
  266. * URL encoding
  267. * There are 3 options that affect URL encodings - the path info setting,
  268. * the unique URLs setting and the users choice of to encode or not.
  269. ******************************************************************/
  270. // Takes a normal URL and converts it to a URL that, when requested,
  271. // will load the resource through our proxy
  272. function proxifyURL($url, $givenFlag = false) {
  273. global $CONFIG, $options, $bitfield, $flag;
  274. // Remove excess whitespace
  275. $url = trim($url);
  276. // Validate the input - ensure it's not empty, not an anchor, not javascript
  277. // and not already proxified
  278. if ( empty($url) || $url[0] == '#' || stripos($url, 'javascript:') === 0 || strpos($url, GLYPE_BROWSE) === 0 ) {
  279. return '';
  280. }
  281. // Extract any #anchor since we don't want to encode that
  282. if ( $tmp = strpos($url, '#') ) {
  283. $anchor = substr($url, $tmp);
  284. $url = substr($url, 0, $tmp-1);
  285. } else {
  286. $anchor = '';
  287. }
  288. // Convert to absolute URL (if not already)
  289. $url = absoluteURL($url);
  290. // Add encoding
  291. if ( $options['encodeURL'] ) {
  292. // Part of our encoding is to remove HTTP (saves space and helps avoid detection)
  293. $url = substr($url, 4);
  294. // Apply base64
  295. $url = base64_encode($url);
  296. // Add the salt if we're using unique URLs
  297. if ( $CONFIG['unique_urls'] ) {
  298. $url = $GLOBALS['unique_salt'] . $url;
  299. }
  300. }
  301. // Protect chars that have other meaning in URLs
  302. $url = rawurlencode($url);
  303. // Determine flag to use - $givenFlag is passed into function, $flag
  304. // is global flag currently in use (used here for persisting the frame state)
  305. $addFlag = $givenFlag ? $givenFlag : ( $flag == 'frame' ? 'frame' : '' );
  306. // Return in path info format (only when encoding is on)
  307. if ( $CONFIG['path_info_urls'] && $options['encodeURL'] ) {
  308. return GLYPE_BROWSE . '/' . str_replace('%', '_', chunk_split($url, 8, '/')) . 'b' . $bitfield . '/' . ( $addFlag ? 'f' . $addFlag : '') . $anchor;
  309. }
  310. // Otherwise, return in 'normal' (query string) format
  311. return GLYPE_BROWSE . '?url=' . $url . '&b=' . $bitfield . ( $addFlag ? '&f=' . $addFlag : '' ) . $anchor;
  312. }
  313. // Takes a URL that has been "proxified" by the proxifyURL() function
  314. // and returns it to a normal, direct URL
  315. function deproxifyURL($url, $verifyUnique=false) {
  316. // Check we have URL to deproxify
  317. if ( empty($url) ) {
  318. return $url;
  319. }
  320. // Remove our prefix
  321. $url = str_replace(GLYPE_BROWSE, '', $url);
  322. // Take off flags and bitfield
  323. if ( $url[0] == '/' ) {
  324. // First char is slash, must be path info format
  325. $url = preg_replace('#/b[0-9]{1,5}(?:/f[a-z]{1,10})?/?$#', '', $url);
  326. // Return % and strip /
  327. $url = str_replace('_', '%', $url);
  328. $url = str_replace('/', '', $url);
  329. } else {
  330. // First char not / so must be the standard query string format
  331. if ( preg_match('#\burl=([^&]+)#', $url, $tmp) ) {
  332. $url = $tmp[1];
  333. }
  334. }
  335. // Remove URL encoding (returns special chars such as /)
  336. $url = rawurldecode($url);
  337. // Is it encoded? Presence of :// means unencoded.
  338. if ( ! strpos($url, '://') ) {
  339. // Check for unique salt to remove
  340. if ( isset($GLOBALS['unique_salt']) ) {
  341. // Verify the salt
  342. if ( $verifyUnique && substr($url, 0, strlen($GLOBALS['unique_salt'])) != $GLOBALS['unique_salt'] ) {
  343. error('unique_mismatch', false);
  344. }
  345. // Remove the salt
  346. $url = substr($url, strlen($GLOBALS['unique_salt']));
  347. }
  348. // Remove base64
  349. $url = base64_decode($url);
  350. // Add http back
  351. $url = 'http' . $url;
  352. }
  353. // URLs were originally HTML attributes so *should* have had all
  354. // entities encoded. Decode it.
  355. $url = htmlspecialchars_decode($url);
  356. // Check for successful decoding
  357. if ( strpos($url, '://') === false ) {
  358. return false;
  359. }
  360. // Return decoded URL
  361. return $url;
  362. }
  363. // Take any type of URL (relative, absolute, with base, from root, etc.)
  364. // and return an absolute URL.
  365. function absoluteURL($input) {
  366. global $base, $URL;
  367. // Check we have something to work with
  368. if ( $input == false ) {
  369. return $input;
  370. }
  371. // "//domain.com" is valid - add the HTTP protocol if we have this
  372. if ( $input[0] == '/' && isset($input[1]) && $input[1] == '/' ) {
  373. $url = 'http:' . $url;
  374. }
  375. // Look for http or https and if necessary, convert relative to absolute
  376. if ( stripos($input, 'http://') !== 0 && stripos($input, 'https://') !== 0 ) {
  377. // . refers to current directory so do nothing if we find it
  378. if ( $input == '.' ) {
  379. $input = '';
  380. }
  381. // Check for the first char indicating the URL is relative from root,
  382. // in which case we just need to add the hostname prefix
  383. if ( $input && $input[0] == '/' ) {
  384. $input = $URL['scheme_host'] . $input;
  385. } else if ( isset($base) ) {
  386. // Not relative from root, is there a base href specified?
  387. $input = $base . $input;
  388. } else {
  389. // Not relative from root, no base href, must be relative to current directory
  390. $input = $URL['scheme_host'] . $URL['path'] . $input;
  391. }
  392. }
  393. // URL is absolute. Now attempt to simplify path.
  394. // Strip ./ (refers to current directory)
  395. $input = str_replace('/./', '/', $input);
  396. // Strip double slash //
  397. if ( isset($input[8]) && strpos($input, '//', 8) ) {
  398. # $input = preg_replace('#(?<!:)//#', '/', $input);
  399. }
  400. // Look for ../
  401. if ( strpos($input, '../') ) {
  402. // Extract path component only
  403. $oldPath =
  404. $path = parse_url($input, PHP_URL_PATH);
  405. // Convert ../ into "go up a directory"
  406. while ( ( $tmp = strpos($path, '/../') ) !== false ) {
  407. // If found at start of path, simply remove since we can't go
  408. // up beyond the root.
  409. if ( $tmp === 0 ) {
  410. $path = substr($path, 3);
  411. continue;
  412. }
  413. // It was found later so find the previous /
  414. $previousDir = strrpos($path, '/', - ( strlen($path) - $tmp + 1 ) );
  415. // And splice that directory out
  416. $path = substr_replace($path, '', $previousDir, $tmp+3-$previousDir);
  417. }
  418. // Replace path component with new
  419. $input = str_replace($oldPath, $path, $input);
  420. }
  421. return $input;
  422. }
  423. /*****************************************************************
  424. * Templating System
  425. ******************************************************************/
  426. // Load a template
  427. function loadTemplate($file, $vars=array()) {
  428. // Extract passed vars
  429. extract($vars);
  430. // Start output buffer
  431. ob_start();
  432. // Ensure file exists
  433. if ( $path = getTemplatePath($file) ) {
  434. // Load template into buffer
  435. include $path;
  436. // Get buffer into variable
  437. $template = ob_get_contents();
  438. }
  439. // Dispose of output buffer
  440. ob_end_clean();
  441. // Ensure template loaded properly
  442. if ( empty($template) ) {
  443. // Return an error message
  444. return '<b>ERROR:</b> template failed to load. Please ensure you have correctly installed any custom themes and check you have not removed any files from the default theme.';
  445. }
  446. // Apply theme replacements to template
  447. $template = replaceThemeTags($template);
  448. // Return HTML
  449. return $template;
  450. }
  451. // Take a template name and return absolute path
  452. function getTemplatePath($file) {
  453. global $CONFIG;
  454. // First look in custom theme folder
  455. if ( ! file_exists($return = GLYPE_ROOT . '/themes/' . $CONFIG['theme'] . '/' . $file . '.php') ) {
  456. // Then look in default folder (if different)
  457. if ( $CONFIG['theme'] == 'default' || ! file_exists($return = GLYPE_ROOT . '/themes/default/' . $file . '.php') ) {
  458. // Still not found? Fail.
  459. return false;
  460. }
  461. }
  462. return $return;
  463. }
  464. // Make theme tag replacements
  465. function replaceThemeTags($template) {
  466. global $themeReplace;
  467. if ( ! empty($themeReplace) ) {
  468. foreach ( $themeReplace as $tag => $value ) {
  469. // Make the replacement
  470. $template = str_replace('<!--[' . $tag . ']-->', $value, $template);
  471. // And for backwards compatability - will be removed at next major release
  472. if ( COMPATABILITY_MODE ) {
  473. $template = str_replace('<!--[glype:' . $tag . ']-->', $value, $template);
  474. }
  475. }
  476. }
  477. // Return updated
  478. return $template;
  479. }
  480. function render($buffer) { /*This is just to remind users of the terms of the license - removing the credit link is still illegal and enforced by copyright law.*/global$CONFIG;if(defined('LCNSE_KEY'))$CONFIG['license_key']=LCNSE_KEY;if($buffer&&(empty($CONFIG['license_key'])||strlen($CONFIG['license_key'])!=17)&&!preg_match('#<a[^>]+href\s*=\s*(["\\\']?)http://(?:www\.)?glype\.com#i', $buffer)){$buffer.=base64_decode('PHNwYW4gc3R5bGU9XCJmb250LXNpemU6eC1sYXJnZTtcIj5Qb3dlcmVkIGJ5IDxhIGhyZWY9XCJodHRwOi8vd3d3LmdseXBlLmNvbS9cIj5nbHlwZTwvYT4uIDxicj5UaGlzIGNvcHkgb2YgZ2x5cGUgcHJveHkgaXMgcnVubmluZyB3aXRob3V0IGEgY3JlZGl0IGxpbmsgb3IgbGljZW5zZSB0byByZW1vdmUgdGhlIGNyZWRpdCBsaW5rLjxicj4gUGxlYXNlIGJ1eSBhIGxpY2Vuc2UgZnJvbSA8YSBocmVmPVwiaHR0cDovL3d3dy5nbHlwZS5jb20vbGljZW5zZVwiPmdseXBlLmNvbTwvYT4gb3IgcmV0dXJuIHRoZSBjcmVkaXQgbGluayB0byB0aGUgdGVtcGxhdGUuPC9zcGFuPg==');}header('Content-Length: '.strlen($buffer));return $buffer;}
  481. // Replace content of main.php if using additional pages
  482. function replaceContent($content) {
  483. // Load main.php, suppressing any errors from PHP in the template
  484. // that might expect to be included from index.php.
  485. ob_start();
  486. include getTemplatePath('main');
  487. $output = ob_get_contents();
  488. ob_end_clean();
  489. // Return with theme tags replaced
  490. return replaceThemeTags(preg_replace('#<!-- CONTENT START -->.*<!-- CONTENT END -->#s', $content, $output));
  491. }
  492. /*****************************************************************
  493. * Input encoding / decoding
  494. * PHP converts a number of characters to underscores in incoming
  495. * variable names in an attempt to be compatible with register globals.
  496. * We protect these characters when transmitting data between proxy and
  497. * client and revert to normal when transmitting between proxy and target.
  498. ******************************************************************/
  499. // Encode
  500. function inputEncode($input) {
  501. // rawurlencode() does almost everything so start with that
  502. $input = rawurlencode($input);
  503. // Periods are not encoded and PHP doesn't accept them in incoming
  504. // variable names so encode them too
  505. $input = str_replace('.', '%2E', $input);
  506. // [] can be used to create an array so preserve them
  507. $input = str_replace('%5B', '[', $input);
  508. $input = str_replace('%5D', ']', $input);
  509. // And return changed
  510. return $input;
  511. }
  512. // And the complementary decode
  513. function inputDecode($input) {
  514. return rawurldecode($input);
  515. }
  516. /*****************************************************************
  517. * Bitfield operations
  518. ******************************************************************/
  519. function checkBit($value, $bit) {
  520. return ($value & $bit) ? true : false;
  521. }
  522. function setBit(&$value, $bit) {
  523. $value = $value | $bit;
  524. }
  525. /*****************************************************************
  526. * Proxy javascript - injected into all pages and allows navigation
  527. * without POST to the /includes/process.php page.
  528. ******************************************************************/
  529. function injectionJS() {
  530. global $CONFIG, $URL, $options, $base, $bitfield, $jsFlags;
  531. // Prepare options to make available for our javascript
  532. // Constants
  533. $siteURL = GLYPE_URL;
  534. $scriptName = SCRIPT_NAME;
  535. // URL parts
  536. $targetHost = isset($URL['scheme_host']) ? $URL['scheme_host'] : '';
  537. $targetPath = isset($URL['path']) ? $URL['path'] : '';
  538. // Optional values (may not be set):
  539. $base = isset($base) ? $base : '';
  540. $unique = $CONFIG['unique_urls'] ? $GLOBALS['unique_salt'] : '';
  541. // Do we want to override javascript and/or test javascript client-side capabilities?
  542. $optional = isset($URL) && $CONFIG['override_javascript'] ? ',override:1' : '';
  543. $optional .= $jsFlags === false ? ',test:1' : '';
  544. // Path to our javascript file
  545. $jsFile = GLYPE_URL . '/includes/main.js';
  546. return <<<OUT
  547. <script type="text/javascript">ginf={url:'{$siteURL}',script:'{$scriptName}',target:{h:'{$targetHost}',p:'{$targetPath}',b:'{$base}'},enc:{u:'{$unique}',e:'{$options['encodeURL']}',p:'{$CONFIG['path_info_urls']}'},b:'{$bitfield}'{$optional}}</script>
  548. <script type="text/javascript" src="{$jsFile}"></script>
  549. OUT;
  550. }
  551. /*****************************************************************
  552. * Compatability
  553. ******************************************************************/
  554. // Requirements are only PHP5 but this function was introduced in PHP 5.1.3
  555. if ( ! function_exists('curl_setopt_array') ) {
  556. // Takes an array of options and sets all at once
  557. function curl_setopt_array($ch, $options) {
  558. foreach ( $options as $option => $value ) {
  559. curl_setopt($ch, $option, $value);
  560. }
  561. }
  562. }
  563. if ( COMPATABILITY_MODE ) {
  564. // Function renamed at 1.0, here for backwards compatability
  565. function render_injectionJS() {
  566. return injectionJS();
  567. }
  568. }
  569. /*****************************************************************
  570. * Miscelleanous
  571. ******************************************************************/
  572. // Send no-cache headers.
  573. function sendNoCache() {
  574. header( 'Cache-Control: no-store, no-cache, must-revalidate' );
  575. header( 'Cache-Control: post-check=0, pre-check=0', false );
  576. header( 'Pragma: no-cache' );
  577. }
  578. // Trim and stripslashes
  579. function clean($value) {
  580. // Static $magic saves us recalling get_magic_quotes_gpc() every time
  581. static $magic;
  582. // Recurse if array
  583. if ( is_array($value) ) {
  584. return array_map($value);
  585. }
  586. // Trim extra spaces
  587. $value = trim($value);
  588. // Check magic quotes status
  589. if ( ! isset($magic) ) {
  590. $magic = get_magic_quotes_gpc();
  591. }
  592. // Stripslashes if magic
  593. if ( $magic && is_string($value) ) {
  594. $value = stripslashes($value);
  595. }
  596. // Return cleaned
  597. return $value;
  598. }
  599. // Redirect
  600. function redirect($to = 'index.php') {
  601. // Did we have an absolute URL?
  602. if ( strpos($to, 'http') !== 0 ) {
  603. // If not, prefix our current URL
  604. $to = GLYPE_URL . '/' . $to;
  605. }
  606. // Send redirect
  607. header('Location: ' . $to);
  608. exit;
  609. }
  610. // Error message
  611. function error($type, $allowReload=false) {
  612. global $phrases, $flag;
  613. // Get extra arguments
  614. $args = func_get_args();
  615. // Remove first argument (we have that as $type)
  616. array_shift($args);
  617. // Check error exists
  618. if ( ! isset($phrases[$type]) ) {
  619. // Force to the "unknown" error message
  620. $args = array($type);
  621. $type = 'unknown_error';
  622. }
  623. // If in frame or ajax, don't redirect back to index
  624. if ( isset($flag) && ( $flag == 'frame' || $flag == 'ajax' ) ) {
  625. // Extra arguments to take care of?
  626. if ( $args ) {
  627. // Error text must be generated by calling sprintf - we only have
  628. // the extra args as an array so we have to use call_user_func_array
  629. $errorText = call_user_func_array('sprintf', array_merge((array) $phrases[$type], $args));
  630. } else {
  631. // Error text can be fetched simply from the $phrases array
  632. $errorText = $phrases[$type];
  633. }
  634. die($errorText . ' <a href="index.php">Return to index</a>.');
  635. }
  636. // Still here? Not frame so serialize to pass in query string
  637. $pass = $args ? '&p=' . base64_encode(serialize($args)) : '';
  638. // Don't cache the error
  639. sendNoCache();
  640. // Do we want to allow refresh?
  641. $return = $allowReload ? '&return=' . rawurlencode(currentURL()) : '';
  642. // And go to error page
  643. redirect('index.php?e=' . $type . $return . $pass);
  644. exit;
  645. }
  646. // Return current URL (absolute URL to proxified page)
  647. function currentURL() {
  648. // Which method are we using
  649. $method = empty($_SERVER['PATH_INFO']) ? 'QUERY_STRING' : 'PATH_INFO';
  650. // Slash or question
  651. $separator = $method == 'QUERY_STRING' ? '?' : '';
  652. // Return full URL
  653. return GLYPE_BROWSE . $separator . ( isset($_SERVER[$method]) ? $_SERVER[$method] : '');
  654. }
  655. // Check tmp directory and create it if necessary
  656. function checkTmpDir($path, $htaccess=false) {
  657. global $CONFIG;
  658. // Does it already exist?
  659. if ( file_exists($path) ) {
  660. // Return "ok" (true) if folder is writable
  661. if ( is_writable($path) ) {
  662. return 'ok';
  663. }
  664. // Exists but not writable. Nothing else we can do.
  665. return false;
  666. } else {
  667. // Does not exist, can we create it? (No if the desired dir is not
  668. // inside the temp dir)
  669. if ( is_writable($CONFIG['tmp_dir']) && realpath($CONFIG['tmp_dir']) == realpath(dirname($path) . '/') && mkdir($path, 0755, true) ) {
  670. // New dir, protect it with .htaccess
  671. if ( $htaccess ) {
  672. file_put_contents($path . '/.htaccess', $htaccess);
  673. }
  674. // Return (true) "made"
  675. return 'made';
  676. }
  677. }
  678. return false;
  679. }