-
-
Save dhaupin/d4fdfb1f0d86099ca5a286283471b01f to your computer and use it in GitHub Desktop.
A deconstructed get_route() hook for CS-Cart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// @@@ DEBUG the x_r() function is here: https://gist.github.com/dhaupin/d9d48328dbe312f6c0de | |
// http://forum.cs-cart.com/topic/47926-seo-addon-301-redirects-making-them-work-when-object-exists-with-same-uri/ | |
/** | |
* "get_route" hook implemetation | |
* @param array &$req input request | |
* @param array &$result result of init function | |
* @param string $area current working area | |
* @param boolean $is_allowed_url Flag that determines if url is supported // note that false triggers a redirect | |
* @return bool true on success, false on failure | |
*/ | |
function fn_seo_get_route(&$req, &$result, &$area, &$is_allowed_url) | |
{ | |
if (($area == 'C') && !$is_allowed_url) { | |
$uri = fn_get_request_uri($_SERVER['REQUEST_URI']); | |
// /test-redirect.html | |
//x_r($uri); | |
if (!empty($uri)) { | |
$rewrite_rules = fn_get_rewrite_rules(); | |
$i = 0; | |
//x_r($rewrite_rules); | |
//x_r(Registry::get('addons.seo.single_url')); // Y | |
//x_r(Registry::get('addons.seo.seo_language')); // N | |
// $rewrite_rules | |
/* | |
[!^()\/(.*\/)?([^\/]+)-page-([0-9]+|full_list)\.(html)$!] => object_name=$matches[3]&page=$matches[4]&sl=$matches[1]&extension=$matches[5] | |
[!^()\/(.*\/)?([^\/]+)\.(html)$!] => object_name=$matches[3]&sl=$matches[1]&extension=$matches[4] | |
[!^()\/(.*\/)?([^\/]+)\/page-([0-9]+|full_list)(\/)?$!] => object_name=$matches[3]&page=$matches[4]&sl=$matches[1] | |
[!^()\/(.*\/)?([^\/?]+)\/?$!] => object_name=$matches[3]&sl=$matches[1] | |
[!^()/$!] => | |
*/ | |
foreach ($rewrite_rules as $pattern => $query) { | |
// increase counter each loop | |
//$i++; | |
if (preg_match($pattern, $uri, $matches) || preg_match($pattern, urldecode($query), $matches)) { | |
// increase count if it matches | |
// login.html page name loops twice | |
// others.html like cats/prods loops once | |
$i++; | |
if ($i == 2) { | |
//x_r($pattern); | |
//x_r($matches); | |
} | |
// login.html loop 1: | |
// !^()\/(.*\/)?([^\/]+)\.(html)$! | |
/* | |
[0] => /login.html | |
[1] => | |
[2] => | |
[3] => login | |
[4] => html | |
*/ | |
// login.html loop 2: | |
// !^()\/(.*\/)?([^\/?]+)\/?$! | |
/* | |
[0] => /login.html | |
[1] => | |
[2] => | |
[3] => login.html | |
*/ | |
$_query = preg_replace("!^.+\?!", '', $query); | |
parse_str($_query, $objects); | |
$result_values = 'matches'; | |
$url_query = ''; | |
if ($i == 1) { | |
//x_r($objects); | |
//x_r($matches[3]); | |
} | |
//x_r($objects); | |
//x_r($matches[3]); | |
// loop 1 - the uri is split with html as seperate entity | |
/* | |
[object_name] => $matches[3] // test-redirect | |
[sl] => $matches[1] // nothing, but i assume would be -en although it doesnt trigger in uri test | |
[extension] => $matches[4] // html | |
*/ | |
// loop 2 - the uri is concatated including html | |
/* | |
[object_name] => $matches[3] | |
[sl] => $matches[1] | |
*/ | |
foreach ($objects as $key => $value) { | |
preg_match('!^.+\[([0-9])+\]$!', $value, $_id); // matches full some-url[23] | |
// here we are converting matches[X] into the values | |
$objects[$key] = (substr($value, 0, 1) == '$') ? ${$result_values}[$_id[1]] : $value; | |
} | |
if ($i == 2) { | |
//x_r($objects); | |
//x_r($matches[3]); | |
} | |
// For the locations wich names stored in the table | |
if (!empty($objects) && !empty($objects['object_name'])) { | |
// this inits since we have a name (url) | |
if (Registry::get('addons.seo.single_url') == 'Y') { | |
// inits cause "single url for all languages" setting is yes | |
$objects['sl'] = (Registry::get('addons.seo.seo_language') == 'Y') ? $objects['sl'] : ''; | |
// sl is blank | |
$objects['sl'] = !empty($req['sl']) ? $req['sl'] : $objects['sl']; | |
//x_r($req); // req is blank | |
} | |
$lang_cond = db_quote("AND lang_code = ?s", !empty($objects['sl']) ? $objects['sl'] : Registry::get('settings.Appearance.frontend_default_language')); | |
// AND lang_code = 'en' | |
$object_type = db_get_field("SELECT type FROM ?:seo_names WHERE name = ?s ?p", $objects['object_name'], fn_get_seo_company_condition('?:seo_names.company_id')); | |
// on pass #2 there is no object type since there is a .html extension | |
if ($i == 2) { | |
//exit('pass number ' . $i); | |
//x_r($object_type); | |
//x_r($objects['object_name']); | |
} | |
//x_r($object_type); // p | |
/* | |
types in schemas/seo/objects.php: | |
c = category (tree) | |
p = product (tree) | |
a = page (tree) | |
e = feature (plain) | |
s = custom (plain) | |
*/ | |
$_seo = db_get_array("SELECT * FROM ?:seo_names WHERE name = ?s ?p ?p", $objects['object_name'], fn_get_seo_company_condition('?:seo_names.company_id', $object_type), $lang_cond); | |
// second loop _seo is still empty | |
if ($i == 2) { | |
//exit('pass number ' . $i); | |
//x_r($_seo); | |
} | |
//x_r($_seo); | |
/* | |
[name] => test-redirect | |
[object_id] => 1594 // product_id | |
[company_id] => 1 | |
[type] => p | |
[dispatch] => | |
[path] => 309 // this is the category_id | |
[lang_code] => en | |
*/ | |
// first pass is full, but this inits on second pass | |
// in the case of a second pass with .html, it prob wont init | |
if (empty($_seo)) { | |
//x_r($objects); | |
//x_r($objects['object_name']); | |
$_seo = db_get_array("SELECT * FROM ?:seo_names WHERE name = ?s ?p", $objects['object_name'], fn_get_seo_company_condition('?:seo_names.company_id')); | |
// its searching for pagetitle.html which doesnt exist in seo_names (most lack html) | |
if ($i == 2) { | |
//exit('pass number ' . $i); | |
//x_r($_seo); | |
} | |
} | |
// second loop _seo is still empty | |
if ($i == 1) { | |
//exit('pass number ' . $i); | |
//x_r($_seo); | |
//x_r($objects); | |
} | |
// first loop _seo is array, second loop is not | |
// first loop has the extension, second does not | |
// this doesnt init for objects | |
if (empty($_seo) && !empty($objects['extension'])) { | |
$_seo = db_get_array("SELECT * FROM ?:seo_names WHERE name = ?s ?p ?p", $objects['object_name'] . '.' . $objects['extension'], fn_get_seo_company_condition('?:seo_names.company_id'), $lang_cond); | |
//x_r('this should not be happening 2'); | |
if (empty($_seo)) { | |
$_seo = db_get_array("SELECT * FROM ?:seo_names WHERE name = ?s ?p", $objects['object_name'] . '.' . $objects['extension'], fn_get_seo_company_condition('?:seo_names.company_id', $object_type)); | |
//x_r('this should not be happening 3'); | |
} | |
} | |
if ($i == 1) { | |
//exit('pass number ' . $i); | |
//x_r($_seo); | |
//x_r($objects); | |
} | |
// _seo loop 1 | |
/* | |
[0] => Array | |
( | |
[name] => test-redirect | |
[object_id] => 1594 | |
[company_id] => 1 | |
[type] => p | |
[dispatch] => | |
[path] => 309 | |
[lang_code] => en | |
) | |
*/ | |
// objects loop 1 | |
/* | |
[object_name] => test-redirect | |
[sl] => | |
[extension] => html | |
*/ | |
// objects loop 2 | |
/* | |
[object_name] => test-redirect.html | |
[sl] => | |
*/ | |
// first loop _seo is array, second loop is not | |
if (!empty($_seo)) { | |
// this is a temp trigger, if it runs, the url triggers rewrite somewhere | |
$_seo_valid = false; | |
// _seo sub counter | |
$ii = 0; | |
foreach ($_seo as $__seo) { // why is this temp | |
$_objects = $objects; | |
$ii++; | |
if (Registry::get('addons.seo.single_url') != 'Y' && empty($_objects['sl'])) { | |
$_objects['sl'] = $__seo['lang_code']; | |
// $_objects is not populated with lang code from $_seo | |
} | |
if (fn_seo_validate_object($__seo, $uri, $_objects) == true) { | |
// fn_seo_validate_object returns a 1 or 0 | |
// it runs as many times as there are _seo array children | |
if ($ii == 1) { | |
//exit('pass number ' . $i); | |
//x_r($_seo); | |
//x_r($objects); | |
} | |
$_seo_valid = true; | |
$_seo = $__seo; | |
$objects = $_objects; | |
// break out of this loop when first valid assimilation is found, pass 1 | |
break; | |
} | |
} // end foreach ($_seo as $__seo) { | |
// end $ii | |
// here after break it does not loop twice | |
if ($i == 1) { | |
//exit('pass number ' . $i); | |
if ($_seo_valid == true) { | |
//exit('$_seo_valid was true on pass ' . $i); | |
} | |
//x_r($_seo); | |
} | |
// first pass this is true, there is no second pass | |
if ($_seo_valid == true) { | |
$req['sl'] = $objects['sl']; | |
$_seo_vars = fn_get_seo_vars($_seo['type']); | |
//x_r(fn_get_seo_vars($_seo['type'])); | |
/* | |
[tree] => 1 | |
[path_function] => Closure Object | |
( | |
[parameter] => Array | |
( | |
[$object_id] => | |
[$company_id] => | |
) | |
) | |
[parent_type] => c | |
[name] => product | |
[picker] => pickers/products/picker.tpl | |
[picker_params] => Array | |
( | |
[type] => single | |
[view_mode] => button | |
) | |
[table] => ?:product_descriptions | |
[description] => product | |
[dispatch] => products.view | |
[item] => product_id | |
[condition] => | |
[not_shared] => 1 | |
[tree_options] => Array | |
( | |
[0] => product_category_nohtml | |
[1] => product_category | |
) | |
[html_options] => Array | |
( | |
[0] => product_category | |
[1] => product_file | |
) | |
[option] => seo_product_type | |
[exist_function] => Closure Object | |
( | |
[parameter] => Array | |
( | |
[$product_id] => | |
[$company_id] => | |
) | |
) | |
*/ | |
// here we build the dispatch and queries into the $req array | |
// $req is used later on http_build_query($req); if the url is not redirect needed | |
if ($_seo['type'] == 's') { // custom seo_name | |
$url_query = $_seo['dispatch']; | |
$req['dispatch'] = $_seo['dispatch']; | |
} else { // if an object was found | |
//$_seo['type'] object type is p | |
// page isnt included in objects for products | |
$page_suffix = (!empty($objects['page'])) ? ('&page=' . $objects['page']) : ''; | |
$url_query = $_seo_vars['dispatch'] . '?' . $_seo_vars['item'] . '=' . $_seo['object_id'] . $page_suffix; | |
// $url_query => products.view?product_id=1594 // followed by pagination | |
//x_r($url_query); | |
$req['dispatch'] = $_seo_vars['dispatch']; | |
// [dispatch] => products.view | |
// @@@@ DH here | |
// set a type for later use? | |
$_type = $object_type; | |
// this doesnt really work well: | |
//$req['type'] = $object_type; | |
} // end type check | |
// object id is set in _seo in first pass | |
// this runs to make =id | |
if (!empty($_seo['object_id'])) { | |
$req[$_seo_vars['item']] = $_seo['object_id']; | |
// $req['product_id'] = 1234; | |
} | |
// page is empty for products | |
if (!empty($objects['page'])) { | |
$req['page'] = $objects['page']; | |
} | |
// @@@@ DH this is normally set without a conditional | |
// This is only init on first pass, type p | |
//* @param boolean $is_allowed_url Flag that determines if url is supported // note that false triggers a redirect | |
/*if ($_type != 's') { | |
$is_allowed_url = false; // this changes master loops to 2 | |
} else { | |
$is_allowed_url = true; // 1 master loop | |
}*/ | |
$is_allowed_url = true; // 1 master loop | |
//x_r($req); | |
/* | |
[sl] => | |
[dispatch] => products.view | |
[product_id] => 1594 | |
*/ | |
} // end if ($_seo_valid == true) { // this was 1 loop, the first | |
} // end if (!empty($_seo)) { // this was 1 loop, the first | |
// For the locations wich names are not in the table | |
} elseif (!empty($objects)) { // end if (!empty($objects) && !empty($objects['object_name'])) { | |
// this shouldnt init since we have a name | |
x_r('you shouldnt be seeing me for products'); | |
if (empty($objects['dispatch'])) { | |
if (!empty($req['dispatch'])) { | |
$req['dispatch'] = is_array($req['dispatch']) ? key($req['dispatch']) : $req['dispatch']; | |
$url_query = $req['dispatch']; | |
} | |
} else { | |
$url_query = $objects['dispatch']; | |
$req['dispatch'] = $objects['dispatch']; | |
} | |
$is_allowed_url = true; | |
if (!empty($objects['sl'])) { | |
$is_allowed_url = false; | |
$req['sl'] = $objects['sl']; | |
if (Registry::get('addons.seo.seo_language') == 'Y') { | |
$lang_statuses = !empty($_SESSION['auth']['area']) && $_SESSION['auth']['area'] == 'A' ? array('A', 'H') : array('A'); | |
$check_language = db_get_field("SELECT count(*) FROM ?:languages WHERE lang_code = ?s AND status IN (?a)", $req['sl'], $lang_statuses); | |
if (!empty($check_language)) { | |
$is_allowed_url = true; | |
} | |
} else { | |
$is_allowed_url = true; | |
} | |
} | |
$req += $objects; | |
// Empty query | |
} else { // end } elseif (!empty($objects)) { | |
$url_query = ''; | |
x_r('you shouldnt be seeing me either'); | |
} // end checks for empty objects | |
// THERE ARE 2 PASSES HERE NOW | |
if ($i == 1) { | |
//exit('pass number ' . $i); | |
if ($is_allowed_url) { | |
//exit($_type); | |
//exit('$is_allowed_url was true on pass ' . $i . ' with type ' . $_type); | |
} | |
//x_r($_seo); | |
} | |
// this inits on neither pass | |
// $is_allowed_url of false means that a redirect should happen. this only runs on true (no redirect) | |
// so this means the break doesnt happen for redirects, hense 2 loops? | |
// note that if (empty($is_allowed_url)) { reduces total loops to 1 | |
//if (empty($is_allowed_url)) { | |
if ($is_allowed_url) { // default | |
$lang_code = empty($objects['sl']) ? Registry::get('settings.Appearance.frontend_default_language') : $objects['sl']; | |
if (empty($req['sl'])) { | |
unset($req['sl']); | |
} | |
$query_string = http_build_query($req); | |
//x_r($url_query); // products.view?product_id=1594 | |
//x_r($query_string); // dispatch=products.view&product_id=1594 | |
$_SERVER['REQUEST_URI'] = fn_url($url_query . '?' . $query_string, 'C', 'rel', $lang_code); | |
// comes out as [REQUEST_URI] => /test-redirect.html | |
// @@@@ this seems incorrect... fn_url could do products.view?product_id=1594 | |
//x_r($url_query . '?' . $query_string); | |
// products.view?product_id=1594?dispatch=products.view&product_id=1594 | |
$_SERVER['QUERY_STRING'] = $query_string; // dispatch=products.view&product_id=1594 | |
$_SERVER['X-SEO-REWRITE'] = true; // [X-SEO-REWRITE] => 1 | |
if ($i == 2) { | |
//x_r('i broke out of master loop at count ' . $i); | |
//x_r($_SERVER); | |
} | |
break; // here is where we break out of regex loops, $i most likely on count 1 | |
} // end if ($is_allowed_url) { // default | |
} // end if (preg_match($pattern, $uri, $matches) || preg_match($pattern, urldecode($query), $matches)) { | |
} // end regexd foreach ($rewrite_rules as $pattern => $query) { | |
// lets spit a loop count | |
if ($i == 1) { | |
//x_r('Master loops: ' . $i); | |
} | |
} // end if (!empty($uri)) { | |
} // end if (($area == 'C') && !$is_allowed_url) { | |
// $i has occured 1 time with defaults | |
if ($i == 1) { | |
//x_r('Total loops: ' . $i); | |
} | |
// @@@ here is where its not working | |
// products arent empty $is_allowed_url | |
// using a type check here causes redir looping, admin side failures, etc | |
if (empty($is_allowed_url)) { // if not allowed url sound like a backwards | |
//if (true) { | |
$query_string = array(); | |
$uri = fn_get_request_uri($_SERVER['REQUEST_URI']); | |
// Attach additinal params to URI if passed | |
if (!empty($_SERVER['QUERY_STRING'])) { | |
parse_str($_SERVER['QUERY_STRING'], $query_string); | |
} | |
// Remove pagination from URI | |
if (preg_match('/\/page-(\d+)\/?$/', $uri, $m)) { | |
$query_string['page'] = $m[1]; | |
$uri = preg_replace('/\/page-\d+\/?$/', '', $uri); | |
} | |
$condition = fn_get_seo_company_condition("?:seo_redirects.company_id"); | |
$redirect_data = db_get_row("SELECT type, object_id, dest, lang_code FROM ?:seo_redirects WHERE src = ?s ?p", $uri, $condition); | |
//x_r($redirect_data); | |
/* | |
[type] => p | |
[object_id] => 1121 // this is what the redirect target is | |
[dest] => | |
[lang_code] => en | |
*/ | |
//x_r(fn_generate_seo_url_from_schema($redirect_data, true, $query_string)); | |
if (!empty($redirect_data)) { | |
$result = array(INIT_STATUS_REDIRECT, fn_generate_seo_url_from_schema($redirect_data, true, $query_string), false, true); | |
} else { | |
$req = array( | |
'dispatch' => '_no_page' | |
); | |
} | |
} // end | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment