From 062d543b2638785c12caaeb4fd9cd66d56573e99 Mon Sep 17 00:00:00 2001
From: Benjamin Dalsass <95754414+bdalsass@users.noreply.github.com>
Date: Mon, 30 Jun 2025 14:19:33 +0200
Subject: [PATCH] =?UTF-8?q?N=C2=B08148=20-=20CAS=20problem=20when=20sendin?=
=?UTF-8?q?g=20a=20link=20ending=20in=20&=20(#722)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
N°8148 - CAS problem when sending a link ending in &
---
application/applicationcontext.class.inc.php | 21 ++++++++--
application/cmdbabstract.class.inc.php | 4 +-
application/dashlet.class.inc.php | 2 +-
application/displayblock.class.inc.php | 41 +++++++++----------
application/utils.inc.php | 8 ++--
core/attributedef.class.inc.php | 8 ++--
core/bulkchange.class.inc.php | 4 +-
core/displayablegraph.class.inc.php | 4 +-
pages/UI.php | 12 +++---
pages/audit.php | 2 +-
pages/schema.php | 6 +--
.../UI/Base/Component/DataTable/DataTable.php | 2 +-
.../Set/BlockLinkSetDisplayAsProperty.php | 4 +-
sources/Controller/AjaxRenderController.php | 4 +-
.../application/ApplicationContextTest.php | 23 +++++++++++
15 files changed, 88 insertions(+), 57 deletions(-)
create mode 100644 tests/php-unit-tests/unitary-tests/application/ApplicationContextTest.php
diff --git a/application/applicationcontext.class.inc.php b/application/applicationcontext.class.inc.php
index 533427e11..ec29db46d 100644
--- a/application/applicationcontext.class.inc.php
+++ b/application/applicationcontext.class.inc.php
@@ -195,16 +195,31 @@ class ApplicationContext
/**
* Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property
+ *
*/
- public function GetForLink()
+ public function GetForLink(bool $bWithLeadingAmpersand = false)
{
+ // If there are no parameters, return an empty string
+ if(empty($this->aValues)){
+ return '';
+ }
+
+ // Build the query string with ampersand separated parameters
$aParams = array();
foreach($this->aValues as $sName => $sValue)
{
$aParams[] = "c[$sName]".'='.urlencode($sValue);
}
- return implode("&", $aParams);
+ $sReturnValue = implode('&', $aParams);
+
+ // add the leading ampersand if requested
+ if($bWithLeadingAmpersand){
+ $sReturnValue = '&' . $sReturnValue;
+ }
+
+ return $sReturnValue;
}
+
/**
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
* Returns the params as c[menu]:..., c[org_id]:....
@@ -382,7 +397,7 @@ class ApplicationContext
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (utils::StrLen($sUrl) > 0) {
if ($bWithNavigationContext) {
- return $sUrl."&".$oAppContext->GetForLink();
+ return $sUrl.$oAppContext->GetForLink(true);
} else {
return $sUrl;
}
diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index bfdbfcdf0..89a07ed65 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -311,7 +311,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
$sParams .= $sName.'='.urlencode($value).'&'; // Always add a trailing &
}
- $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/'.$oObj->GetUIPage().'?'.$sParams.'class='.get_class($oObj).'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink().'&a=1';
+ $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/'.$oObj->GetUIPage().'?'.$sParams.'class='.get_class($oObj).'&id='.$oObj->getKey().$oAppContext->GetForLink(true).'&a=1';
$oPage->add_early_script(<<add($oAppContext->GetForForm());
// Hook the cancel button via jQuery so that it can be unhooked easily as well if needed
- $sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_form&class='.$sClass.'&'.$oAppContext->GetForLink();
+ $sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_form&class='.$sClass.$oAppContext->GetForLink(true);
$sCancelButtonOnClickScript = "let fOnClick{$this->m_iFormId}CancelButton = ";
if(isset($aExtraParams['js_handlers']['cancel_button_on_click'])){
diff --git a/application/dashlet.class.inc.php b/application/dashlet.class.inc.php
index 4126cb0b5..e25766268 100644
--- a/application/dashlet.class.inc.php
+++ b/application/dashlet.class.inc.php
@@ -2138,7 +2138,7 @@ class DashletHeaderDynamic extends Dashlet
$oSet = new DBObjectSet($oFilter);
$iCount = $oSet->Count();
$oAppContext = new ApplicationContext();
- $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
+ $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($oFilter->serialize());
$oSubTitle->AddHtml(''.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'');
return $oPanel;
diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php
index 12a0fe18e..0c0e5d0c5 100644
--- a/application/displayblock.class.inc.php
+++ b/application/displayblock.class.inc.php
@@ -1124,7 +1124,7 @@ JS
$oSingleGroupByValueFilter->SetShowObsoleteData($this->m_bShowObsoleteData);
}
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
- .'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
+ .'pages/UI.php?operation=search'.$oAppContext->GetForLink(true)
.'&filter='.rawurlencode($oSingleGroupByValueFilter->serialize());
$aCounts[$sStateValue] = ['link' => $sHyperlink, 'label' => $aCounts[$sStateValue]];
}
@@ -1232,7 +1232,7 @@ JS
$iCount = $this->m_oSet->Count();
$sClassLabel = MetaModel::GetName($sClass);
$sClassIconUrl = MetaModel::GetClassIcon($sClass, false);
- $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
+ $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($this->m_oFilter->serialize());
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
$aRefreshParams = [
@@ -1241,7 +1241,7 @@ JS
];
if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY)) {
- $sCreateActionUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.'&'.$oAppContext->GetForLink();
+ $sCreateActionUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.$oAppContext->GetForLink(true);
$sCreateActionLabel = Dict::Format('UI:Button:Create');
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, $sCreateActionUrl,
$sCreateActionLabel, $aRefreshParams);
@@ -1289,7 +1289,7 @@ JS
$aData = array();
$oAppContext = new ApplicationContext();
- $sParams = $oAppContext->GetForLink();
+ $sParams = $oAppContext->GetForLink(true);
foreach ($aGroupBy as $iRow => $iCount) {
// Build the search for this subset
$oSubsetSearch = $this->m_oFilter->DeepClone();
@@ -1304,7 +1304,7 @@ JS
$aData[] = array(
'group' => $aLabels[$iRow],
- 'value' => "$iCount"
+ 'value' => "$iCount"
); // TO DO: add the context information
}
$aAttribs = array(
@@ -1636,7 +1636,7 @@ JS
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
$sFilter = $this->m_oFilter->serialize(false, $aQueryParams);
$oContext = new ApplicationContext();
- $sContextParam = $oContext->GetForLink();
+ $sContextParam = $oContext->GetForLink(true);
$sAggregationFunction = isset($aExtraParams['aggregation_function']) ? $aExtraParams['aggregation_function'] : '';
$sAggregationAttr = isset($aExtraParams['aggregation_attribute']) ? $aExtraParams['aggregation_attribute'] : '';
$sLimit = isset($aExtraParams['limit']) ? $aExtraParams['limit'] : '';
@@ -1644,7 +1644,7 @@ JS
$sOrderDirection = isset($aExtraParams['order_direction']) ? $aExtraParams['order_direction'] : '';
if (isset($aExtraParams['group_by_label'])) {
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sChartId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam;
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sChartId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).$sContextParam;
} else {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sChartId{$iChartCounter}¶ms[order_direction]=$sOrderDirection¶ms[order_by]=$sOrderBy¶ms[limit]=$sLimit¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam;
}
@@ -1681,11 +1681,14 @@ JS
$oBlock = null;
$sJSURLs = '';
+ $oContext = new ApplicationContext();
+ $sContextParam = $oContext->GetForLink(true);
+
if (isset($aExtraParams['group_by'])) {
$this->MakeGroupByQuery($aExtraParams, $oGroupByExp, $sGroupByLabel, $aGroupBy, $sAggregationFunction, $sFctVar, $sAggregationAttr, $sSql);
$aRes = CMDBSource::QueryToArray($sSql);
- $oContext = new ApplicationContext();
- $sContextParam = $oContext->GetForLink();
+
+
$iTotalCount = 0;
$aURLs = array();
@@ -1705,14 +1708,14 @@ JS
$oSubsetSearch = $this->m_oFilter->DeepClone();
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
$oSubsetSearch->AddConditionExpression($oCondition);
- $aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
+ $aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).$sContextParam;
}
$sJSURLs = json_encode($aURLs);
}
if (isset($aExtraParams['group_by_label'])) {
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$aExtraParams[group_by]¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$aExtraParams[currentId]¶ms[order_direction]=$aExtraParams[order_direction]¶ms[order_by]=$aExtraParams[order_by]¶ms[limit]=$aExtraParams[limit]¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).'&'.$sContextParam;
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$aExtraParams[group_by]¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$aExtraParams[currentId]¶ms[order_direction]=$aExtraParams[order_direction]¶ms[order_by]=$aExtraParams[order_by]¶ms[limit]=$aExtraParams[limit]¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).$sContextParam;
} else {
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$aExtraParams[group_by]¶ms[chart_type]=$sChartType¶ms[currentId]=$aExtraParams[currentId]¶ms[order_direction]=$aExtraParams[order_direction]¶ms[order_by]=$aExtraParams[order_by]¶ms[limit]=$aExtraParams[limit]¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).'&'.$sContextParam;
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$aExtraParams[group_by]¶ms[chart_type]=$sChartType¶ms[currentId]=$aExtraParams[currentId]¶ms[order_direction]=$aExtraParams[order_direction]¶ms[order_by]=$aExtraParams[order_by]¶ms[limit]=$aExtraParams[limit]¶ms[aggregation_function]=$sAggregationFunction¶ms[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).$sContextParam;
}
switch ($sChartType) {
@@ -1785,7 +1788,7 @@ JS
$oBlock->sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
$oBlock->sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($oBlock->sCsvFile);
- $oBlock->sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
+ $oBlock->sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
// Pass the parameters via POST, since expression may be very long
$aParamsToPost = array(
'expression' => $this->m_oFilter->ToOQL(true),
@@ -1885,10 +1888,7 @@ class MenuBlock extends DisplayBlock
&& (!isset($aExtraParams['menu']) || $aExtraParams['menu'] === "1" || $aExtraParams['menu'] === true)
) {
$oAppContext = new ApplicationContext();
- $sContext = $oAppContext->GetForLink();
- if (utils::IsNotNullOrEmptyString($sContext)) {
- $sContext = '&'.$sContext;
- }
+ $sContext = $oAppContext->GetForLink(true);
$sFilter = $this->GetFilter()->serialize();
@@ -2578,11 +2578,8 @@ class MenuBlock extends DisplayBlock
$sUrl = "{$sRootUrl}pages/{$sUIPage}?{$sUrlParams}";
$oAppContext = new ApplicationContext();
- $sContext = $oAppContext->GetForLink();
- if (utils::IsNotNullOrEmptyString($sContext)) {
- $sUrl .= '&'.$sContext;
- }
+ $sContext = $oAppContext->GetForLink(true);
- return $sUrl;
+ return $sUrl . $sContext;
}
}
diff --git a/application/utils.inc.php b/application/utils.inc.php
index 5803a3bc8..649483a68 100644
--- a/application/utils.inc.php
+++ b/application/utils.inc.php
@@ -1516,12 +1516,12 @@ class utils
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
/** @var \DBObjectSet $param */
$oAppContext = new ApplicationContext();
- $sContext = $oAppContext->GetForLink();
+ $sContext = $oAppContext->GetForLink(true);
$sDataTableId = is_null($sDataTableId) ? '' : $sDataTableId;
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
$sFilter = urlencode($param->GetFilter()->serialize());
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$oContainerBlock->AddJsFileRelPath('js/tabularfieldsselector.js');
$oContainerBlock->AddJsFileRelPath('js/jquery.dragtable.js');
$oContainerBlock->AddCssFileRelPath('css/dragtable.css');
@@ -1696,8 +1696,8 @@ class utils
$oAppContext = new ApplicationContext();
$sUrl = $sAppRootUrl
- .'pages/UI.php?operation=search&'
- .$oAppContext->GetForLink()
+ .'pages/UI.php?operation=search'
+ .$oAppContext->GetForLink(true)
.'&filter='.rawurlencode($oDataTableSearchFilter->serialize());
$sUrl .= '&aParams='.rawurlencode($sParams); // Not working... yet, cause not handled by UI.php
diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index ea4568b15..cce290954 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -10954,12 +10954,12 @@ abstract class AttributeSet extends AttributeDBFieldVoid
$sDescription = utils::EscapeHtml($this->GetValueDescription($sValue));
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sValue'");
$oAppContext = new ApplicationContext();
- $sContext = $oAppContext->GetForLink();
+ $sContext = $oAppContext->GetForLink(true);
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($oFilter->GetClass());
$sFilter = rawurlencode($oFilter->serialize());
$sLink = '';
if ($bWithLink && $this->bDisplayLink) {
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$sLink = ' href="'.$sUrl.'"';
}
@@ -12276,13 +12276,13 @@ class AttributeTagSet extends AttributeSet
$sTagDescription = $oTag->Get('description');
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sTagCode'");
$oAppContext = new ApplicationContext();
- $sContext = $oAppContext->GetForLink();
+ $sContext = $oAppContext->GetForLink(true);
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($oFilter->GetClass());
$sFilter = rawurlencode($oFilter->serialize());
$sLink = '';
if ($bWithLink && $this->bDisplayLink) {
- $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
+ $sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$sLink = ' href="'.$sUrl.'"';
}
diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php
index ee6014324..df6a238e5 100644
--- a/core/bulkchange.class.inc.php
+++ b/core/bulkchange.class.inc.php
@@ -1406,7 +1406,7 @@ class BulkChange
$aDetails = array();
while ($oChange = $oBulkChanges->Fetch())
{
- $sDate = ''.$oChange->Get('date').'';
+ $sDate = ''.$oChange->Get('date').'';
$sUser = $oChange->GetUserName();
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
{
@@ -1488,7 +1488,7 @@ EOF
function OnTruncatedHistoryToggle(bShowAll)
{
$('#csv_history_reload').html('
');
- $.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
+ $.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sAppContext', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
{
$('#$sAjaxDivId').html(data);
}
diff --git a/core/displayablegraph.class.inc.php b/core/displayablegraph.class.inc.php
index b7fbe7475..cf354f135 100644
--- a/core/displayablegraph.class.inc.php
+++ b/core/displayablegraph.class.inc.php
@@ -1470,8 +1470,8 @@ class DisplayableGraph extends SimpleGraph
try {
$this->InitFromGraphviz();
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
- $sContext = $oAppContext->GetForLink();
- $sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
+ $sContext = $oAppContext->GetForLink(true);
+ $sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s'.$sContext;
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sAttachmentExportTitle = '';
diff --git a/pages/UI.php b/pages/UI.php
index 732b23f26..c8efc163e 100644
--- a/pages/UI.php
+++ b/pages/UI.php
@@ -90,7 +90,7 @@ function ApplyNextAction(Webpage $oP, CMDBObject $oObj, $sNextAction)
$oAppContext = new ApplicationContext();
//echo "Missing Attributes
".print_r($aExpectedAttributes, true)."
\n";
- $oP->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=stimulus&class='.get_class($oObj).'&stimulus='.$sNextAction.'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink());
+ $oP->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=stimulus&class='.get_class($oObj).'&stimulus='.$sNextAction.'&id='.$oObj->getKey().$oAppContext->GetForLink(true));
}
}
@@ -101,7 +101,7 @@ function ReloadAndDisplay($oPage, $oObj, $sMessageId = '', $sMessage = '', $sSev
{
cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), $sMessageId, $sMessage, $sSeverity, 0, true /* must not exist */);
}
- $oPage->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.get_class($oObj).'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink());
+ $oPage->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.get_class($oObj).'&id='.$oObj->getKey().$oAppContext->GetForLink(true));
}
/**
@@ -993,7 +993,7 @@ try
$oForm->AddHtml($oP->GetDetails($aDetails));
$oForm->AddHtml('');
- $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter).$oAppContext->GetForLink(true);
$oCancelButton = ButtonUIBlockFactory::MakeForCancel(Dict::S('UI:Button:Cancel'), 'cancel', 'cancel');
$oCancelButton->SetOnClickJsCode("window.location.href='$sURL'");
$oForm->AddSubBlock($oCancelButton);
@@ -1165,7 +1165,7 @@ try
$oP->AddUiBlock($oBlock);
// Back to the list
- $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter).$oAppContext->GetForLink(true);
$oSubmitButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:Button:Done'), 'submit', 'submit', true);
$oSubmitButton->SetOnClickJsCode("window.location.href='$sURL'");
$oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
@@ -1606,7 +1606,7 @@ class UI
// Add user filter
$oFullSetFilter->UpdateContextFromUser();
$aSelectedObj = utils::ReadMultipleSelection($oFullSetFilter);
- $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter).$oAppContext->GetForLink(true);
$aContext = array('filter' => utils::EscapeHtml($sFilter));
cmdbAbstractObject::DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $sCancelUrl, array(), $aContext);
}
@@ -1640,7 +1640,7 @@ class UI
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObj'));
}
$aSelectedObj = explode(',', $sSelectedObj);
- $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter).$oAppContext->GetForLink(true);
$aContext = array(
'filter' => utils::EscapeHtml($sFilter),
'selectObj' => $sSelectedObj,
diff --git a/pages/audit.php b/pages/audit.php
index ed952ebbf..f4c705d31 100644
--- a/pages/audit.php
+++ b/pages/audit.php
@@ -436,7 +436,7 @@ try
foreach ($aErrors as $aErrorRow) {
$aObjectsWithErrors[$aErrorRow['id']] = true;
}
- $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">
";
+ $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey().$oAppContext->GetForLink(true)."\">$iErrorsCount GetKey()."&rule=".$oAuditRule->GetKey().$oAppContext->GetForLink(true)."\">
";
$aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount));
$aRow['class'] = $oAuditCategory->GetReportColor($iCount, $iErrorsCount);
}
diff --git a/pages/schema.php b/pages/schema.php
index b6051b322..343c7bcb5 100644
--- a/pages/schema.php
+++ b/pages/schema.php
@@ -1174,11 +1174,7 @@ EOF
$oAppContext = new ApplicationContext();
-$sContext = $oAppContext->GetForLink();
-if (!empty($sContext))
-{
- $sContext = '&'.$sContext;
-}
+$sContext = $oAppContext->GetForLink(true);
$operation = utils::ReadParam('operation', '');
$oLayout = new PageContentWithSideContent();
diff --git a/sources/Application/UI/Base/Component/DataTable/DataTable.php b/sources/Application/UI/Base/Component/DataTable/DataTable.php
index ff4277716..03d3d8835 100644
--- a/sources/Application/UI/Base/Component/DataTable/DataTable.php
+++ b/sources/Application/UI/Base/Component/DataTable/DataTable.php
@@ -99,7 +99,7 @@ class DataTable extends UIContentBlock
{
$oAppContext = new ApplicationContext();
if(strpos ($sAjaxUrl,'?')) {
- $this->sAjaxUrl = $sAjaxUrl."&".$oAppContext->GetForLink();
+ $this->sAjaxUrl = $sAjaxUrl.$oAppContext->GetForLink(true);
} else {
$this->sAjaxUrl = $sAjaxUrl."?".$oAppContext->GetForLink();
}
diff --git a/sources/Application/UI/Links/Set/BlockLinkSetDisplayAsProperty.php b/sources/Application/UI/Links/Set/BlockLinkSetDisplayAsProperty.php
index 4dad47e81..39cef28c9 100644
--- a/sources/Application/UI/Links/Set/BlockLinkSetDisplayAsProperty.php
+++ b/sources/Application/UI/Links/Set/BlockLinkSetDisplayAsProperty.php
@@ -97,7 +97,7 @@ class BlockLinkSetDisplayAsProperty extends UIContentBlock
$this->oTwigEnv = TwigHelper::GetTwigEnvironment(TwigHelper::ENUM_TEMPLATES_BASE_PATH_BACKOFFICE);
$oAppContext = new ApplicationContext();
- $this->sAppContext = $oAppContext->GetForLink();
+ $this->sAppContext = $oAppContext->GetForLink(true);
$this->sUIPage = cmdbAbstractObject::ComputeStandardUIPage($this->sTargetClass);
}
@@ -160,7 +160,7 @@ class BlockLinkSetDisplayAsProperty extends UIContentBlock
{
return ' href="'
.utils::GetAbsoluteUrlAppRoot()
- ."pages/$this->sUIPage?operation=details&class=$this->sTargetClass&id=$id&$this->sAppContext"
+ ."pages/$this->sUIPage?operation=details&class=$this->sTargetClass&id=$id$this->sAppContext"
.'" target="_self"';
}
}
\ No newline at end of file
diff --git a/sources/Controller/AjaxRenderController.php b/sources/Controller/AjaxRenderController.php
index 8ca0967e2..f6b2dc18d 100644
--- a/sources/Controller/AjaxRenderController.php
+++ b/sources/Controller/AjaxRenderController.php
@@ -640,7 +640,7 @@ class AjaxRenderController
$aResult = array();
$oAppContext = new ApplicationContext();
- $sParams = $oAppContext->GetForLink();
+ $sParams = $oAppContext->GetForLink(true);
foreach ($aGroupBy as $iRow => $iCount) {
// Build the search for this subset
$oSubsetSearch = $oFilter->DeepClone();
@@ -655,7 +655,7 @@ class AjaxRenderController
$aResult[] = array(
'group' => $aLabels[$iRow],
- 'value' => "$iCount",
+ 'value' => "$iCount",
); // TO DO: add the context information
}
diff --git a/tests/php-unit-tests/unitary-tests/application/ApplicationContextTest.php b/tests/php-unit-tests/unitary-tests/application/ApplicationContextTest.php
new file mode 100644
index 000000000..78c6aa30f
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/application/ApplicationContextTest.php
@@ -0,0 +1,23 @@
+GetForLink(true);
+ $this->assertEquals($sExpected, $sActual, 'Query parameters string should include all request parameters prefixed with &');
+
+ $sExpected = 'c[org_id]=3&c[menu]=TargetOverview';
+ $sActual = $oApplicationContext->GetForLink();
+ $this->assertEquals($sExpected, $sActual, 'Query parameters string should not start with & when $bIncludeAmpersand is false');
+ }
+
+}
\ No newline at end of file