/**
  * Check to ensure a permalink is correct
  * Accepts a second value of TRUE to simply return a boolean (TRUE means permalink is OK, false means it is not)
  * By default, it takes action based on your settings
  *
  * @access	public
  * @param	string		Correct SEO title (app_dir)
  * @param	boolean		[TRUE, return a boolean (true for OK, false for not). FALSE {default} simply take action based on settings]
  * @return	boolean
  */
 public function checkPermalink($seoTitle, $return = FALSE)
 {
     /* Only serve GET requests */
     if ($this->request['request_method'] != 'get') {
         return FALSE;
     }
     if (!$this->settings['use_friendly_urls'] or !$seoTitle or !$this->settings['seo_bad_url'] or $this->settings['seo_bad_url'] == 'nothing') {
         return FALSE;
     }
     $_st = $this->seoTemplates['__data__']['start'];
     $_end = $this->seoTemplates['__data__']['end'];
     $_sep = $this->seoTemplates['__data__']['varSep'];
     $_blk = $this->seoTemplates['__data__']['varBlock'];
     $_qs = $_SERVER['QUERY_STRING'] ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
     $_uri = $_SERVER['REQUEST_URI'] ? $_SERVER['REQUEST_URI'] : @getenv('REQUEST_URI');
     $_toTest = $_qs ? $_qs : $_uri;
     /* Shouldn't need to check this, but feel better for doing it: Friendly URL? */
     if (!strstr($_toTest, $_end)) {
         return FALSE;
     }
     /* Try original */
     if (!preg_match("#" . $_st . preg_quote($seoTitle, '#') . '(' . $_end . "\$|" . preg_quote($_blk, '#') . ")#", $_toTest)) {
         /* Do we need to encode? */
         $_toTest = urldecode($_toTest);
     }
     if (!preg_match("#" . $_st . preg_quote($seoTitle, '#') . '(' . $_end . "\$|" . preg_quote($_blk, '#') . ")#", $_toTest)) {
         if ($return === TRUE) {
             return FALSE;
         }
         /* Still here? */
         switch ($this->settings['seo_bad_url']) {
             default:
             case 'meta':
                 $this->addMetaTag('robots', 'noindex,nofollow');
                 break;
             case 'redirect':
                 $uri = array();
                 foreach ($this->seoTemplates as $key => $data) {
                     if (!$data['in']['regex']) {
                         continue;
                     }
                     if (preg_match($data['in']['regex'], $_toTest, $matches)) {
                         if (is_array($data['in']['matches'])) {
                             foreach ($data['in']['matches'] as $_replace) {
                                 $k = IPSText::parseCleanKey($_replace[0]);
                                 if (strstr($_replace[1], '$')) {
                                     $v = IPSText::parseCleanValue($matches[intval(str_replace('$', '', $_replace[1]))]);
                                 } else {
                                     $v = IPSText::parseCleanValue($_replace[1]);
                                 }
                                 $uri[] = $k . '=' . $v;
                             }
                         }
                         if (strstr($_toTest, $_blk)) {
                             $_parse = substr($_toTest, strrpos($_toTest, $_blk) + strlen($_blk));
                             $_data = explode($_sep, $_parse);
                             $_c = 0;
                             foreach ($_data as $_v) {
                                 if (!$_c) {
                                     $k = IPSText::parseCleanKey($_v);
                                     $v = '';
                                     $_c++;
                                 } else {
                                     $v = IPSText::parseCleanValue($_v);
                                     $_c = 0;
                                     $uri[] = $k . '=' . $v;
                                 }
                             }
                         }
                         break;
                     }
                 }
                 /* Got something? */
                 if (count($uri)) {
                     $newurl = $this->registry->getClass('output')->formatUrl($this->registry->getClass('output')->buildUrl(implode('&', $uri), 'public'), $seoTitle, $key);
                     if ($this->settings['base_url'] . $_toTest != $newurl) {
                         $this->registry->getClass('output')->silentRedirect($newurl, $seoTitle, TRUE);
                     }
                 } else {
                     return FALSE;
                 }
                 break;
         }
     }
     return TRUE;
 }
 /**
  * Check to ensure a permalink is correct
  * Accepts a second value of TRUE to simply return a boolean (TRUE means permalink is OK, false means it is not)
  * By default, it takes action based on your settings
  *
  * @access	public
  * @param	string		Correct SEO title (app_dir)
  * @param	boolean		[TRUE, return a boolean (true for OK, false for not). FALSE {default} simply take action based on settings]
  * @return	boolean
  */
 public function checkPermalink($seoTitle, $return = FALSE)
 {
     /* Only serve GET requests */
     if ($this->request['request_method'] != 'get') {
         return FALSE;
     }
     if (!$this->settings['use_friendly_urls'] or !$seoTitle) {
         return FALSE;
     }
     $_st = $this->seoTemplates['__data__']['start'];
     $_end = $this->seoTemplates['__data__']['end'];
     $_sep = $this->seoTemplates['__data__']['varSep'];
     $_join = $this->seoTemplates['__data__']['varJoin'];
     $_blk = $this->seoTemplates['__data__']['varBlock'];
     $_qs = $_SERVER['QUERY_STRING'] ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
     $_uri = $_SERVER['REQUEST_URI'] ? $_SERVER['REQUEST_URI'] : @getenv('REQUEST_URI');
     $seoTitle = !empty($seoTitle) && !is_array($seoTitle) ? array($seoTitle) : $seoTitle;
     /* Bug Fix: #20279 */
     if ($this->settings['htaccess_mod_rewrite'] && strpos($_uri, IPS_PUBLIC_SCRIPT . '?/')) {
         $this->registry->getClass('output')->silentRedirect($this->settings['board_url'] . $_qs, $seoTitle, TRUE);
     }
     $_toTest = $_uri ? $_uri : $_qs;
     /* Now we need to strip off the beginning path so we are left with just the FURL part */
     $_path = parse_url($this->settings['board_url'], PHP_URL_PATH);
     $_toTest = ($_path and $_path != '/') ? preg_replace("#^{$_path}#", '', $_toTest) : $_toTest;
     $_encodedManually = false;
     /* Shouldn't need to check this, but feel better for doing it: Friendly URL? */
     if (!strstr($_toTest, $_end)) {
         return FALSE;
     }
     /* Got index.php in the URL? */
     if (!$this->settings['htaccess_mod_rewrite']) {
         $_toTest = str_replace(IPS_PUBLIC_SCRIPT . '/', '', $_toTest);
     }
     // Removing this - see http://community.invisionpower.com/resources/bugs.html/_/ip-board/topic-furl-redirect-r37445 and http://community.invisionpower.com/resources/bugs.html/_/ip-board/transliteration-r37146
     // -- Just a note if this is ever restored for some reason - it does not support $seoTitle as array (i.e. for status updates)
     //
     // /* If the SEO title has %hex but the incoming URL doesn't, convert the incoming URL */
     /*if ( strstr( $seoTitle[0], '%' ) && ! strstr( $_toTest, '%' ) )
     	 {
      		 $_toTest 		  = urlencode( $_toTest );
      		 $_encodedManually = true;
     	 	
     	 }*/
     /* @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/having-a-followed-by-a-number-%23-in-a-topic-title-breaks-furl-redirection-r41229 */
     foreach ($seoTitle as $essEeeOh) {
         if (strstr($essEeeOh, '%') && IPS_DOC_CHAR_SET != 'UTF-8') {
             $_encodedManually = true;
         }
     }
     /* Does it contain unicode? */
     if (strstr($_toTest, '%')) {
         /* Lowercase it as some browsers send %E2 but it will be stored as %e2 */
         $_toTest = strtolower($_toTest);
     }
     /* Try original */
     if ($_encodedManually === false && (is_array($seoTitle) or !preg_match("#" . $_st . preg_quote($seoTitle[0], '#') . '(' . $_end . '$|/\\?|' . $_end . '\\w+?' . $_end . "\$|" . preg_quote($_blk, '#') . ")#", $_toTest))) {
         /* Do we need to encode? */
         $_toTest = urldecode($_toTest);
     }
     if ($this->settings['url_type'] == 'query_string') {
         $_toTest = str_replace(IPS_PUBLIC_SCRIPT . '?/', '', $_toTest);
         // This ends up making /statuses/id/2 (for instance) as statuses/id/2 and does not match FURL templates
         //$_toTest = ltrim( $_toTest, '/' );
     }
     #print '#\d+?' . $_st . preg_quote( $seoTitle, '#' ) . '(' . $_end . "$|" . $_end . "\w+?" . $_end . "$|" . preg_quote( $_blk, '#' ) . ")#";exit;
     if (is_array($seoTitle) or !preg_match('#\\d+?' . $_st . preg_quote($seoTitle, '#') . '(' . $_end . "\$|" . $_end . '\\w+?' . $_end . '$|/\\?|' . preg_quote($_blk, '#') . ")#", $_toTest)) {
         if ($return === TRUE) {
             return FALSE;
         }
         $uri = array();
         $storeKey = '';
         $storeData = '';
         foreach ($this->seoTemplates as $key => $data) {
             if (!$data['in']['regex']) {
                 continue;
             }
             $data['in']['regex'] = str_replace("\\{__varBlock__\\}", preg_quote($_blk, '#'), $data['in']['regex']);
             if (preg_match($data['in']['regex'], $_toTest, $matches)) {
                 $storeKey = $key;
                 $storeData = $data;
                 $pageNumber = null;
                 /* Handling pages as a special thing? */
                 if ($data['isPagesMode'] && strstr($_toTest, $this->seoTemplates['__data__']['varPage'])) {
                     preg_match('#(' . preg_quote($this->seoTemplates['__data__']['varPage'], '#') . '(\\d+?))(?:$|' . preg_quote($this->seoTemplates['__data__']['varBlock'], '#') . ')#', $_toTest, $pageMatches);
                     if ($pageMatches[1]) {
                         $pageNumber = intval($pageMatches[2]);
                         /* We want page-1 to 301 to just / */
                         $pageNumber = $pageNumber > 1 ? $pageNumber : null;
                     }
                 }
                 if (is_array($data['in']['matches'])) {
                     foreach ($this->seoTemplates[$key]['in']['matches'] as $_replace) {
                         $k = IPSText::parseCleanKey($_replace[0]);
                         if (strstr($_replace[1], '$')) {
                             $v = IPSText::parseCleanValue($matches[intval(str_replace('$', '', $_replace[1]))]);
                         } else {
                             $v = IPSText::parseCleanValue($_replace[1]);
                         }
                         $uri[] = $k . '=' . $v;
                     }
                 }
                 if (strstr($_toTest, $_blk)) {
                     $_parse = substr($_toTest, strrpos($_toTest, $_blk) + strlen($_blk));
                     $_data = explode($_sep, $_parse);
                     $_c = 0;
                     foreach ($_data as $_v) {
                         list($__k, $__v) = explode($_join, $_v);
                         $k = IPSText::parseCleanKey($__k);
                         $v = IPSText::parseCleanValue($__v);
                         $uri[] = $k . '=' . $v;
                     }
                 }
                 if ($data['newTemplate']) {
                     $key = $data['newTemplate'];
                 }
                 break;
             }
         }
         /* Got something? */
         if (count($uri)) {
             if ($pageNumber !== null) {
                 /* add in page */
                 $uri[] = 'page=' . $pageNumber;
             }
             foreach ($seoTitle as $_k => $_v) {
                 if (preg_match('#\\&[\\#a-z0-9]{2,6};#i', $_v)) {
                     $seoTitle[$_k] = urlencode($_v);
                 }
             }
             $newurl = $this->registry->getClass('output')->formatUrl($this->registry->getClass('output')->buildUrl(implode('&', $uri), 'public'), $seoTitle, $key);
             $base_url = (!IN_ACP and $this->member->session_type != 'cookie') ? preg_replace("/s=([a-zA-Z0-9]{32})(&|&)/", '', $this->settings['base_url']) : $this->settings['base_url'];
             switch ($this->settings['url_type']) {
                 case 'path_info':
                     if ($this->settings['htaccess_mod_rewrite']) {
                         $base_url = str_replace(IPS_PUBLIC_SCRIPT . '?', '', $base_url);
                     } else {
                         $base_url = str_replace(IPS_PUBLIC_SCRIPT . '?', IPS_PUBLIC_SCRIPT . '/', $base_url);
                     }
                     break;
                 default:
                 case 'query_string':
                     $base_url = str_replace(IPS_PUBLIC_SCRIPT . '?', IPS_PUBLIC_SCRIPT . '?/', $base_url);
                     break;
             }
             $base_url = rtrim($base_url, '/');
             /* preg_match is to prevent redirecting in older Android and IE browsers (Does not affect IE10).  They will take %c5%82, break down to separate characters and re-encode as %c3%85%c2%82, creating
             			an infinite redirect loop.  Ticket 848516, 853009 and @link http://community.invisionpower.com/resources/bugs.html/_/ip-board/urls-with-multi-byte-characters-causing-infinite-redirect-on-old-android-devices-r41601 */
             if ($base_url . $_toTest != $newurl and !preg_match("/(android 2|msie)/i", $this->member->user_agent)) {
                 /* Load information file */
                 if ($storeData['app'] && is_file(IPSLib::getAppDir($storeData['app']) . '/extensions/furlRedirect.php')) {
                     $_class = IPSLib::loadLibrary(IPSLib::getAppDir($storeData['app']) . '/extensions/furlRedirect.php', 'furlRedirect_' . $storeData['app'], $storeData['app']);
                     $_furl = new $_class(ipsRegistry::instance());
                     $_testUrl = strstr($this->settings['base_url'], '?') ? $this->settings['base_url'] . implode('&', $uri) : $this->settings['base_url'] . '?' . implode('&', $uri);
                     $_furl->setKeyByUri($_testUrl);
                     $_seoTitle = $_furl->fetchSeoTitle();
                     if (preg_match('#\\&[\\#a-z0-9]{2,6};#i', $_seoTitle)) {
                         $_seoTitle = urlencode($_seoTitle);
                     }
                     if ($_seoTitle && empty($this->request['debug'])) {
                         $this->registry->getClass('output')->silentRedirect($_testUrl, $_seoTitle, true, $storeKey);
                     } else {
                         $this->registry->getClass('output')->silentRedirect($_testUrl, $seoTitle, TRUE, $key);
                     }
                 } else {
                     $this->registry->getClass('output')->silentRedirect($newurl, $seoTitle, TRUE, $key);
                 }
             }
         } else {
             return FALSE;
         }
     }
     return TRUE;
 }
 /**
  * INIT furls
  * Performs set up and figures out any incoming links
  *
  * @return	@e void
  */
 protected static function _fUrlInit()
 {
     /**
      * Fix request uri
      */
     self::_fixRequestUri();
     if (ipsRegistry::$settings['use_friendly_urls']) {
         /* Grab and store accessing URL */
         self::$_uri = preg_replace("/s=(&|\$)/", '', str_replace('/?', '/' . IPS_PUBLIC_SCRIPT . '?', $_SERVER['REQUEST_URI']));
         $_urlBits = array();
         /* Grab FURL data... */
         if (!IN_DEV and is_file(FURL_CACHE_PATH)) {
             $templates = array();
             include FURL_CACHE_PATH;
             /*noLibHook*/
             self::$_seoTemplates = $templates;
         } else {
             /* Attempt to write it */
             self::$_seoTemplates = IPSLib::buildFurlTemplates();
             try {
                 IPSLib::cacheFurlTemplates();
             } catch (Exception $e) {
             }
         }
         if (is_array(self::$_seoTemplates) and count(self::$_seoTemplates)) {
             $uri = $_SERVER['REQUEST_URI'] ? $_SERVER['REQUEST_URI'] : @getenv('REQUEST_URI');
             /* Bug 21295 - remove known URL from test URI */
             $_t = !empty(ipsRegistry::$settings['board_url']) ? @parse_url(ipsRegistry::$settings['board_url']) : @parse_url(ipsRegistry::$settings['base_url']);
             $_toTest = ($_t['path'] and $_t['path'] != '/') ? preg_replace("#^{$_t['path']}#", '', $uri) : str_replace($_t['scheme'] . '://' . $_t['host'], '', $uri);
             $_404Check = $_toTest;
             //We want to retain any /index.php for this test later in this block of code
             $_toTest = str_ireplace(array('//' . IPS_PUBLIC_SCRIPT . '?', '/' . IPS_PUBLIC_SCRIPT . '?', '/' . IPS_PUBLIC_SCRIPT), '', $_toTest);
             $_gotMatch = false;
             foreach (self::$_seoTemplates as $key => $data) {
                 if (empty($data['in']['regex'])) {
                     continue;
                 }
                 /* Clean up regex */
                 $data['in']['regex'] = str_replace('#{__varBlock__}', preg_quote(self::$_seoTemplates['__data__']['varBlock'], '#'), $data['in']['regex']);
                 if (preg_match($data['in']['regex'], $_toTest, $matches)) {
                     $_gotMatch = true;
                     /* Handling pages as a special thing? */
                     if ($data['isPagesMode']) {
                         if (strstr($_toTest, self::$_seoTemplates['__data__']['varPage'])) {
                             preg_match('#(' . preg_quote(self::$_seoTemplates['__data__']['varPage'], '#') . '(\\d+?))(?:$|' . preg_quote(self::$_seoTemplates['__data__']['varBlock'], '#') . ')#', $_toTest, $pageMatches);
                             if ($pageMatches[1]) {
                                 $k = 'page';
                                 $_GET[$k] = intval($pageMatches[2]);
                                 $_POST[$k] = intval($pageMatches[2]);
                                 $_REQUEST[$k] = intval($pageMatches[2]);
                                 $_urlBits[$k] = intval($pageMatches[2]);
                                 ipsRegistry::$request[$k] = intval($pageMatches[2]);
                                 $_toTest = str_replace($pageMatches[1], '', $_toTest);
                             }
                         } else {
                             /* Redirect all < 3.4 links to the new sexy awesome format if need be */
                             if (self::$_seoTemplates['__data__']['varBlock'] != '/page__' && $uri && strstr($uri, '/page__')) {
                                 preg_match('#(.*)(page__.*)$#', $uri, $matches);
                                 $url = $matches[1];
                                 $query = $matches[2];
                                 $newQuery = '?';
                                 $data = explode('__', substr($query, 6));
                                 for ($i = 0, $j = count($data); $i < $j; $i++) {
                                     $newQuery .= ($i % 2 == 0 ? '&' : '=') . $data[$i];
                                 }
                                 /* Class output not created here */
                                 header("HTTP/1.1 301 Moved Permanently");
                                 header("Location: " . $_t['scheme'] . '://' . $_t['host'] . $url . $newQuery);
                                 exit;
                             }
                         }
                     }
                     if (is_array($data['in']['matches'])) {
                         foreach ($data['in']['matches'] as $_replace) {
                             $k = IPSText::parseCleanKey($_replace[0]);
                             if (strpos($_replace[1], '$') !== false) {
                                 $v = IPSText::parseCleanValue($matches[intval(str_replace('$', '', $_replace[1]))]);
                             } else {
                                 $v = IPSText::parseCleanValue($_replace[1]);
                             }
                             $_GET[$k] = $v;
                             $_POST[$k] = $v;
                             $_REQUEST[$k] = $v;
                             $_urlBits[$k] = $v;
                             ipsRegistry::$request[$k] = $v;
                         }
                     }
                     if (strpos($_toTest, self::$_seoTemplates['__data__']['varBlock']) !== false) {
                         /* Changed how the input variables are parsed based on feedback in bug report 24907
                            @link http://community.invisionpower.com/tracker/issue-24907-member-list-pagination-not-work-with-checkbox
                            Input variables now preserve array depth properly as a result */
                         $_parse = substr($_toTest, strpos($_toTest, self::$_seoTemplates['__data__']['varBlock']) + strlen(self::$_seoTemplates['__data__']['varBlock']));
                         $_data = explode(self::$_seoTemplates['__data__']['varSep'], $_parse);
                         $_query = '';
                         foreach ($_data as $line) {
                             list($k, $v) = explode(self::$_seoTemplates['__data__']['varJoin'], $line);
                             $_query .= $k . '=' . $v . '&';
                         }
                         $_data = array();
                         parse_str($_query, $_data);
                         $_data = IPSLib::parseIncomingRecursively($_data);
                         foreach ($_data as $k => $v) {
                             $_GET[$k] = $v;
                             $_POST[$k] = $v;
                             $_REQUEST[$k] = $v;
                             $_urlBits[$k] = $v;
                             ipsRegistry::$request[$k] = $v;
                         }
                     }
                     break;
                 }
             }
             /* Check against the original request for 404 error */
             $_404checkPass = false;
             if (!strstr($_404Check, '&') and !strstr($_404Check, '=') and (strstr($_404Check, IPS_PUBLIC_SCRIPT . '?/') or !strstr($_404Check, '.php'))) {
                 $_404checkPass = true;
             }
             if (strstr($_404Check, '/' . IPS_PUBLIC_SCRIPT)) {
                 if (preg_match("#(.+?)/" . preg_quote(IPS_PUBLIC_SCRIPT) . "#", $_404Check, $matches) and !is_file(DOC_IPS_ROOT_PATH . preg_replace('/(.+?)\\?.+/', '$1', $_404Check))) {
                     $_404checkPass = true;
                 }
             }
             /* Got a match? */
             if (!defined('CCS_GATEWAY_CALLED') and !defined('IPS_ENFORCE_ACCESS') and !defined('LOFIVERSION_CALLED') and IPS_IS_MOBILE_APP === false and IPS_DEFAULT_PUBLIC_APP == 'forums' and $_gotMatch === false and $_toTest and $_toTest != '/' and $_toTest != '/?' and $_404checkPass) {
                 self::$_noFurlMatch = true;
             }
             //-----------------------------------------
             // If using query string furl, extract any
             // secondary query string.
             // Ex: http://localhost/index.php?/path/file.html?key=value
             // Will pull the key=value properly
             //-----------------------------------------
             $_qmCount = substr_count($_toTest, '?');
             /* We don't want to check for secondary query strings in the ACP */
             if (!IN_ACP && $_qmCount > 1) {
                 $_secondQueryString = substr($_toTest, strrpos($_toTest, '?') + 1);
                 $_secondParams = explode('&', $_secondQueryString);
                 if (count($_secondParams)) {
                     foreach ($_secondParams as $_param) {
                         list($k, $v) = explode('=', $_param);
                         $k = IPSText::parseCleanKey($k);
                         $v = IPSText::parseCleanValue($v);
                         $_GET[$k] = $v;
                         $_REQUEST[$k] = $v;
                         $_urlBits[$k] = $v;
                         ipsRegistry::$request[$k] = $v;
                     }
                 }
             }
             /* Process URL bits for extra ? in them */
             /* We don't want to check for secondary query strings in the ACP */
             if (!IN_ACP && is_array($_GET) and count($_GET)) {
                 foreach ($_GET as $k => $v) {
                     /* Nexus sends &url=.... as a parameter, which can have a ? in it, but we don't want to strip that out of the parameter or consider those values part of the input */
                     if ($k == 'url') {
                         continue;
                     }
                     if (!is_array($v) and strstr($v, '?')) {
                         list($rvalue, $more) = explode('?', $v);
                         if ($rvalue and $more) {
                             //$k	= IPSText::parseCleanKey( $_k );
                             //$v	= IPSText::parseCleanValue( $_v );
                             /* Reset key with correct value */
                             $_v = IPSText::parseCleanValue($rvalue);
                             $_GET[$k] = $_v;
                             $_REQUEST[$k] = $_v;
                             $_urlBits[$k] = $_v;
                             ipsRegistry::$request[$k] = $_v;
                             /* Now add in the other value */
                             if (strstr($more, '=')) {
                                 list($_k, $_v) = explode('=', $more);
                                 if ($_k and $_v) {
                                     $_GET[$_k] = $_v;
                                     $_REQUEST[$_k] = $_v;
                                     $_urlBits[$_k] = $_v;
                                     ipsRegistry::$request[$_k] = $_v;
                                 }
                             }
                         }
                     }
                 }
             }
         }
         /* Reformat basic URL */
         if (is_array($_urlBits)) {
             ipsRegistry::$settings['query_string_real'] = trim(http_build_query($_urlBits), '&');
         }
     }
 }
Beispiel #4
0
 /**
  * Try and deconstruct the link if it's a FURRY FURL
  *
  * @access	protected
  * @param	string		Incoming URL
  * @return	array		Array of request data or false
  */
 protected function _checkForFurl($url)
 {
     $_urlBits = array();
     $_toTest = $url;
     $templates = array();
     if (is_file(FURL_CACHE_PATH)) {
         $templates = array();
         require FURL_CACHE_PATH;
         /*noLibHook*/
         $_seoTemplates = $templates;
     } else {
         /* Attempt to write it */
         $_seoTemplates = IPSLib::buildFurlTemplates();
         try {
             IPSLib::cacheFurlTemplates();
         } catch (Exception $e) {
         }
     }
     if (is_array($_seoTemplates) and count($_seoTemplates)) {
         foreach ($_seoTemplates as $key => $data) {
             if (empty($data['in']['regex'])) {
                 continue;
             }
             if (preg_match($data['in']['regex'], $_toTest, $matches)) {
                 if (is_array($data['in']['matches'])) {
                     foreach ($data['in']['matches'] as $_replace) {
                         $k = IPSText::parseCleanKey($_replace[0]);
                         if (strpos($_replace[1], '$') !== false) {
                             $v = IPSText::parseCleanValue($matches[intval(str_replace('$', '', $_replace[1]))]);
                         } else {
                             $v = IPSText::parseCleanValue($_replace[1]);
                         }
                         $_urlBits[$k] = $v;
                     }
                 }
                 if (strpos($_toTest, $_seoTemplates['__data__']['varBlock']) !== false) {
                     $_parse = substr($_toTest, strpos($_toTest, $_seoTemplates['__data__']['varBlock']) + strlen($_seoTemplates['__data__']['varBlock']));
                     $_data = explode($_seoTemplates['__data__']['varSep'], $_parse);
                     $_c = 0;
                     foreach ($_data as $_v) {
                         if (!$_c) {
                             $k = IPSText::parseCleanKey($_v);
                             $v = '';
                             $_c++;
                         } else {
                             $v = IPSText::parseCleanValue($_v);
                             $_c = 0;
                             $_urlBits[$k] = $v;
                         }
                     }
                 }
                 break;
             }
         }
         //-----------------------------------------
         // If using query string furl, extract any
         // secondary query string.
         // Ex: http://localhost/index.php?/path/file.html?key=value
         // Will pull the key=value properly
         //-----------------------------------------
         $_qmCount = substr_count($_toTest, '?');
         if ($_qmCount > 1) {
             $_secondQueryString = substr($_toTest, strrpos($_toTest, '?') + 1);
             $_secondParams = explode('&', $_secondQueryString);
             if (count($_secondParams)) {
                 foreach ($_secondParams as $_param) {
                     list($k, $v) = explode('=', $_param);
                     $k = IPSText::parseCleanKey($k);
                     $v = IPSText::parseCleanValue($v);
                     $_urlBits[$k] = $v;
                 }
             }
         }
         /* Process URL bits for extra ? in them */
         if (is_array($_urlBits) and count($_urlBits)) {
             foreach ($_urlBits as $k => $v) {
                 if (strstr($v, '?')) {
                     list($rvalue, $more) = explode('?', $v);
                     if ($rvalue and $more) {
                         /* Reset key with correct value */
                         $_v = $rvalue;
                         $_urlBits[$k] = $_v;
                         /* Now add in the other value */
                         if (strstr($more, '=')) {
                             list($_k, $_v) = explode('=', $more);
                             if ($_k and $_v) {
                                 $_urlBits[$_k] = $_v;
                             }
                         }
                     }
                 }
             }
         }
     }
     return count($_urlBits) ? $_urlBits : false;
 }
 /**
  * Recursively cleans keys and values and
  * inserts them into the input array
  *
  * @access	public
  * @param	mixed		Input data
  * @param	array		Storage array for cleaned data
  * @param	integer		Current iteration
  * @return	array 		Cleaned data
  */
 public static function parseIncomingRecursively(&$data, $input = array(), $iteration = 0)
 {
     // Crafty hacker could send something like &foo[][][][][][]....to kill Apache process
     // We should never have an input array deeper than 20..
     if ($iteration >= 20) {
         return $input;
     }
     foreach ($data as $k => $v) {
         if (is_array($v)) {
             $input[$k] = self::parseIncomingRecursively($data[$k], array(), ++$iteration);
         } else {
             $k = IPSText::parseCleanKey($k);
             $v = IPSText::parseCleanValue($v, false);
             $input[$k] = $v;
         }
     }
     return $input;
 }