plugins\urleditor\urleditor.admin.php

<?php
/* ====================
[BEGIN_COT_EXT]
Hooks=tools
[END_COT_EXT]
==================== */
 
/**
 * Overloads standard cot_url() function and loads URL
 * transformation rules
 *
 * @package URLEditor
 * @copyright (c) Cotonti Team
 * @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
 */
 
(defined('COT_CODE') && defined('COT_ADMIN')) or die('Wrong URL.');
 
list($usr['auth_read'], $usr['auth_write'], $usr['isadmin']) = cot_auth('plug', 'urleditor');
cot_block($usr['isadmin']);
 
$t = new XTemplate(cot_tplfile('urleditor.admin', 'plug', true));
 
require_once cot_incfile('forms');
require_once cot_langfile('urleditor', 'plug');
 
$adminhelp = $L['adm_help_urls'];
$adminsubtitle = $L['adm_urls'];
 
$a = cot_import('a', 'G', 'ALP');
 
$site_uri = COT_SITE_URI;
 
// Server type detection
if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false)
{
	$serv_type = 'apache';
	$conf_name = '.htaccess';
	$hta_prefix = <<<END
# Rewrite engine options
Options FollowSymLinks -Indexes
RewriteEngine On
# Server-relative path to Cotonti:
RewriteBase "$site_uri"
END;
	$hta_flags = '[QSA,NC,NE,L]';
	$hta_rule = 'RewriteRule';
	$hta_postfix = '';
	$rb = '^';
	$re = '';
	$loc = '';
	$hta_error = 'ErrorDocument';
}
elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false)
{
	$serv_type = 'iis';
	$conf_name = 'IsapiRewrite4.ini';
	$hta_prefix = '';
	$hta_flags = '[I,L]';
	$hta_rule = 'RewriteRule';
	$hta_postfix = '';
	$rb = '^/';
	$re = '';
	$loc = '/';
}
elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false)
{
	$serv_type = 'nginx';
	$conf_name = 'nginx.conf';
	$loc = $site_uri;
	if($site_uri[0] != '/') $loc = '/'.$loc;
	if($site_uri[mb_strlen($site_uri) - 1] != '/') $loc .= '/';
	$hta_prefix = '';
	$hta_flags = 'last;';
	$hta_rule = 'rewrite';
	$rb = '"^'.$loc;
	$re = '"';
	$hta_error = 'error_page';
}
else
{
	$serv_type = 'unknown';
}
 
/* === Hook === */
foreach (cot_getextplugins('admin.urls.first') as $pl)
{
	include $pl;
}
/* ===== */
 
if ($a == 'save' && is_writable('./datas/urltrans.dat'))
{
	// Fetch data
	$ut_area = cot_import('area', 'P', 'ARR');
	$ut_params = cot_import('params', 'P', 'ARR');
	$ut_format = cot_import('format', 'P', 'ARR');
	$htaccess = cot_import('htaccess', 'P', 'BOL');
 
	/* === Hook === */
	foreach (cot_getextplugins('admin.urls.save') as $pl)
	{
		include $pl;
	}
	/* ===== */
 
	// Write header
	$fp = fopen('./datas/urltrans.dat', 'w');
	// Process and write
	$count = count($ut_area);
	// If the table is empty, restore the default rule
	if($count == 0)
	{
		$ut_area = array('*');
		$ut_params = array('*');
		$ut_format = array('{$_area}.php');
		$count = 1;
	}
	// Continue processing
	$hta = empty($hta_prefix) ? '' : $hta_prefix . "\n";
	$var_pattern = '[^/&?#]+';
	$mainurl = parse_url($cfg['mainurl']);
	$host = preg_quote($mainurl['host']);
	$path = preg_quote(COT_SITE_URI);
	// Pepend rules to fix static data when using dynamic categories
	if($serv_type != 'nginx')
	{
		$hta .= $hta_rule . ' ' . $rb . '(datas|images|js|themes)/(.*)$' . $re . ' ' . $loc . '$1/$2' . ' ' . $hta_flags . "\n";
	}
	for($i = 0; $i < $count; $i++)
	{
		if(empty($ut_format[$i]) || empty($ut_params[$i]))
		{
			// Ignore empty rules
			continue;
		}
		// Write the rule to urltrans.dat
		fputs($fp, $ut_area[$i] . "\t" . $ut_params[$i] . "\t" . $ut_format[$i] . "\n");
		if($ut_area[$i] == '*' && $ut_params[$i] == '*' && $ut_format[$i] == '{$_area}.php')
		{
			// Default rule doesn't need any rewrite rules
			continue;
		}
        $has_callbacks = false;
		if(preg_match('#\{[\w_]+\(\)\}#', $ut_format[$i]))
		{
			// Rule with callback, requires custom rewrite
			cot_message($L['adm_urls_callbacks'] . ': ' . htmlspecialchars($ut_format[$i]), 'warning');
            $has_callbacks = true;
			continue;
		}
        if ($has_callbacks)
        {
            cot_message('adm_urls_errors');
        }
		// Remove unsets
		$ut_format[$i] = preg_replace('#\{\!\$.+?\}#', '', $ut_format[$i]);
		// Set some defaults
		$hta_line = $hta_rule . ' ' . $rb;
		$format = $ut_format[$i];
		$area = $ut_area[$i] == '*' ? $var_pattern : $ut_area[$i];
		mb_parse_str($ut_params[$i], $params);
		$j = 0;
		$k = 0;
		$m_count = 0;
		$qs = '';
		$area_sub = '';
		if(preg_match('#^https?\://([^/]+)/(.*)$#', $format, $mt)/* && $serv_type == 'apache'*/)
		{
			// Subdomains support
			$format = $mt[2];
			$pattern = preg_quote($mt[2]);
			$rhost = $mt[1];
			$hta_host = preg_quote($rhost);
			if(preg_match_all('#\{\$(\w+)\}#', $rhost, $mt, PREG_SET_ORDER))
			{
				// Perform domain submask substitutions
				$mm_count = count($mt);
				$jj = 0;
				$kk = 0;
				for($jj = 0; $jj < $mm_count; $jj++)
				{
					$key = $mt[$jj][1];
					if($key == '_area')
					{
						if($area != $var_pattern)
						{
							$hta_host = str_replace(preg_quote($mt[$jj][0]), preg_quote($area), $hta_host);
							$kk++;
						}
						else
						{
							$hta_host = str_replace(preg_quote($mt[$jj][0]), '('.$area.')', $hta_host);
							$area_sub = '%' . ($jj - $kk + 1);
						}
					}
					elseif($key == '_host')
					{
						$hta_host = str_replace(preg_quote($mt[$jj][0]), $host, $hta_host);
						$kk++;
					}
					else
					{
						$hta_host = str_replace(preg_quote($mt[$jj][0]), '('.$var_pattern.')', $hta_host);
						$qs .= '&' . $key . '=%' . ($jj - $kk + 1);
						unset($params[$key]);
					}
				}
			}
			$hta .= "RewriteCond %{HTTP_HOST} ^$hta_host$ [NC]\n";
		}
		else
		{
			$pattern = preg_quote($format);
		}
		if(preg_match_all('#\{\$(\w+)\}#', $format, $mt, PREG_SET_ORDER))
		{
			// Perform substitutions for variables used in format
			$m_count = count($mt);
			for($j = 0; $j < $m_count; $j++)
			{
				$key = $mt[$j][1];
				if($key == '_area')
				{
					if($area != $var_pattern)
					{
						$pattern = str_replace(preg_quote($mt[$j][0]), preg_quote($area), $pattern);
						$k++;
					}
					else
					{
						$pattern = str_replace(preg_quote($mt[$j][0]), '('.$area.')', $pattern);
						$area_sub = '$' . ($j - $k + 1);
					}
				}
				elseif($key == '_host')
				{
					$pattern = str_replace(preg_quote($mt[$j][0]), $host, $pattern);
					$k++;
				}
				elseif($key == '_rhost')
				{
					$pattern = str_replace(preg_quote($mt[$j][0]), $var_pattern, $pattern);
					$k++;
				}
				elseif($key == '_path')
				{
					$pattern = str_replace(preg_quote($mt[$j][0]), $path, $pattern);
					$k++;
				}
				else
				{
					$pattern = str_replace(preg_quote($mt[$j][0]), '('.$var_pattern.')', $pattern);
					$qs .= '&' . $key . '=$' . ($j - $k + 1);
					unset($params[$key]);
				}
			}
		}
		// Complete the query string with static paramaters set but not used in format
		if(count($params) > 0)
		{
			foreach($params as $key => $val)
			{
				if ($key != '*' && $val != '*' && mb_strpos($val, '|') === false)
				{
					$qs .= '&' . $key . '=' . urlencode($val);
				}
			}
		}
		// Correct the query string
		if (mb_strpos($format, '?') !== false)
		{
			if(empty($qs))
			{
				$qs = mb_substr($format, mb_strpos($format, '?'));
			}
			else
			{
				$qs = mb_substr($format, mb_strpos($format, '?')) . $qs;
			}
		}
		elseif(!empty($qs))
		{
			$qs[0] = '?';
		}
		// Finalize the rewrite rule
		$pattern .= '(.*)$';
		$qs .= '$'. ($m_count - $k + 1);
		$area = empty($area_sub) ? $area : $area_sub;
		$hta_line .= $pattern . $re . ' ' . $loc . $area . '.php' . $qs . ' ' . $hta_flags;
		$hta .= $hta_line . "\n";
	}
	fclose($fp);
	if($htaccess)
	{
		$custom_htaccess = cot_import('custom_htaccess', 'P', 'NOC');
		$htdata = file_get_contents('.htaccess');
		if (mb_strpos($htdata, "\n### COTONTI URLTRANS ###\n") !== false)
		{
			$htparts = explode("\n### COTONTI URLTRANS ###\n", $htdata);
			$htparts[1] = $hta;
			if (count($htparts) == 3)
			{
				$htparts[3] = $htparts[2];
			}
			$htparts[2] = $custom_htaccess;
		}
		else
		{
			$htparts[0] = $htdata;
			$htparts[1] = $hta;
			$htparts[2] = $custom_htaccess;
			$htparts[3] = '';
		}
		$htdata = implode("\n### COTONTI URLTRANS ###\n", $htparts);
		file_put_contents('.htaccess', $htdata);
		$hta = $htdata;
	}
 
	$t->assign(array(
		'ADMIN_URLS_CONF_NAME' => $conf_name,
		'ADMIN_URLS_HTA' => $hta
	));
	$t->parse('MAIN.HTA');
 
	$cache && $cache->db->remove('cot_urltrans', 'system');
}
 
// Check urltrans.dat
if(!is_writeable('./datas/urltrans.dat'))
{
	cot_error('adm_urls_error_dat');
}
 
// Get list of valid areas
$areas = array('*', 'plug', 'login');
$res = $db->query("SELECT ct_code FROM $db_core WHERE ct_plug = 0 ORDER BY ct_code");
foreach ($res->fetchAll() as $row)
{
	$areas[] = $row['ct_code'];
}
sort($areas);
 
/* FIXME: check block / actualize as not exists in template --------------------- */
// New rule contents
foreach($areas as $ar)
{
	$t->assign(array(
		'ADMIN_URLS_AREABOX_SELECTED' => ($ar == '*') ? ' selected="selected"' : '',
		'ADMIN_URLS_AREABOX_ITEM' => $ar
	));
	$t->parse('MAIN.AREABOX');
}
/* FIXME: [end_of_block] --------------------------------------------- */
 
if (is_readable('./datas/urltrans.dat'))
{
	$fp = fopen('./datas/urltrans.dat', 'r');
	// Rules
	$ii = 0;
	/* === Hook - Part1 : Set === */
	$extp = cot_getextplugins('admin.urls.loop');
	/* ===== */
	while($line = trim(fgets($fp), " \t\r\n"))
	{
		$parts = preg_split('#\s+#', $line);
 
		$t->assign(array(
			'ADMIN_URLS_ROW_I' => $ii,
			'ADMIN_URLS_ROW_AREAS' => cot_selectbox($parts[0], 'area[]', $areas, $areas, false),
			'ADMIN_URLS_ROW_PARTS1' => cot_inputbox('text', 'params[]', $parts[1]),
			'ADMIN_URLS_ROW_PARTS2' => cot_inputbox('text', 'format[]', $parts[2]),
			'ADMIN_URLS_ROW_ODDEVEN' => cot_build_oddeven($ii)
		));
 
		/* === Hook - Part2 : Include === */
		foreach ($extp as $pl)
		{
			include $pl;
		}
		/* ===== */
 
		$t->parse('MAIN.ROW');
		$ii++;
	}
	fclose($fp);
}
 
$htaccess = ($serv_type == 'apache' && is_writeable('./'.$conf_name)) ? true : false;
if ($htaccess)
{
	$htdata = file_get_contents('.htaccess');
	$htparts = explode("\n### COTONTI URLTRANS ###\n", $htdata);
	if (count($htparts) == 4)
	{
		$t->assign('ADMIN_URLS_CUSTOM_HTACCESS', $htparts[2]);
	}
}
 
// Error and message reporting
cot_display_messages($t);
 
$t->assign(array(
	'ADMIN_URLS_II' => $ii,
	'ADMIN_URLS_FORM_URL' => cot_url('admin', 'm=other&p=urleditor&a=save'),
	'ADMIN_URLS_ROW_AREAS' => cot_selectbox('*', 'area[]', $areas, $areas, false),
	'ADMIN_URLS_ROW_PARTS1' => cot_inputbox('text', 'params[]', ''),
	'ADMIN_URLS_ROW_PARTS2' => cot_inputbox('text', 'format[]', ''),
	'ADMIN_URLS_ROW_ODDEVEN' => cot_build_oddeven($ii)
));
 
/* === Hook  === */
foreach (cot_getextplugins('admin.urls.tags') as $pl)
{
	include $pl;
}
/* ===== */
 
$t->parse('MAIN');
$adminmain = $t->text('MAIN');