Compare commits

...

24 Commits

Author SHA1 Message Date
v-dumas
f29b6d571d N°9347 - Change Cloud class icon location 2026-03-13 15:41:29 +01:00
v-dumas
7aaf3da4d5 N°9347 - Get Software logo as SoftwareInstance icon 2026-03-13 15:40:42 +01:00
v-dumas
a810f3b79f N°9347 - Enable icon of some CIs by instance 2026-03-13 11:07:37 +01:00
v-dumas
44ac2fbce2 N°9138 - fix greptile feedbacks 2026-03-12 10:46:17 +01:00
v-dumas
8ccf9cffef N°9138 - Align presentation details of Software classes 2026-03-11 17:51:00 +01:00
v-dumas
f6378088be N°9138 - Align presentation details of CMDB classes 2026-03-11 15:56:09 +01:00
v-dumas
3dd1c11d3b N°9304 - Add quick links to access impact analysis by default 2026-03-10 13:28:04 +01:00
Benjamin DALSASS
b3613b6c4b Merge remote-tracking branch 'origin/support/3.2' into develop 2026-03-09 08:42:39 +01:00
Benjamin Dalsass
ab8e7bd15e N°9236 - tag admin fix (#832) 2026-03-09 08:30:39 +01:00
lenaick.moreira
307c308eb0 Fix unit test testPhpMinVersionConsistency 2026-03-05 16:15:18 +01:00
Lenaick
61e5536b50 N°9234 - Sanitize query expression parameter in suggested OQL on run query page (#829) 2026-03-05 16:02:30 +01:00
Lenaick
104dd1970f N°9230 - Sanitize dashboard_id parameter in "revert_dashboard" operation of AJAX render function (#828) 2026-03-05 15:55:28 +01:00
Stephen Abello
884d64a42a Remove hardcoded colors from non theme file and replace hardcoded value with variable 2026-03-05 15:35:49 +01:00
Stephen Abello
44c0a025a8 Merge branch 'support/3.2' into develop
# Conflicts:
#	datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig
2026-03-05 15:32:35 +01:00
Stephen Abello
929b8b9eca Fix CI by fixing code style 2026-03-05 15:28:27 +01:00
Stephen Abello
3b8e079cf1 N°6977 - Sanitize Excel formulas in exports (#818)
* N°6977 - Sanitize Excel formulas in export in the backoffice
---------

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2026-03-05 15:07:27 +01:00
lenaick.moreira
36247ba0ee Fix unit test testPhpMinVersionConsistency 2026-03-02 15:30:30 +01:00
lenaick.moreira
091d99b08f PHP CS Fixer 2026-03-02 15:19:31 +01:00
lenaick.moreira
3c60a80f9b Fix error on CI
* Call to undefined method PhpParser\ConstExprEvaluator::setStaticcallsWhitelist()
2026-03-02 14:55:12 +01:00
lenaick.moreira
ae633111c0 Merge remote-tracking branch 'origin/support/3.2' into develop 2026-03-02 14:50:14 +01:00
Molkobain
52a1d8d626 📝 Update developers.md to fix php static analysis link 2026-03-02 09:55:05 +01:00
Molkobain
3a64e3bb9e 📝 Update README.md to point to a new "Developers" page 2026-03-02 09:52:36 +01:00
Lenaick
fc967c06ce N°8834 - Add compatibility with PHP 8.4 (#819)
* N°8834 - Add compatibility with PHP 8.4

* Rollback of scssphp/scssphp version upgrade due to compilation error
2026-02-26 10:36:32 +01:00
Eric Espie
d4821b7edc remove log level config 2026-02-26 10:19:34 +01:00
185 changed files with 5157 additions and 3097 deletions

9
.doc/developers.md Normal file
View File

@@ -0,0 +1,9 @@
# Developers
## PHP Code Styles
We use `PHP CS Fixer` to ensure code formating consistency across PHP codebase.
You can find the configuration and instructions to run it [here](../tests/php-code-style/README.md).
## PHP Static Analysis
We use `PHPStan` to ensure code quality and to detect potential bugs in our PHP codebase.
You can find the configuration and instructions to run it [here](../tests/php-static-analysis/README.md).

View File

@@ -73,6 +73,9 @@ iTop development is sponsored, led, and supported by [Combodo][0].
[0]: https://www.combodo.com
## Developers
You can find information and instructions about our quality tools and how to run them [here](.doc/developers.md).
## Contributors

View File

@@ -967,7 +967,9 @@ CSS;
}
}
}
array_map(function ($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults);
array_map(function ($sVariableValue) {
return ltrim($sVariableValue);
}, $aVariablesResults);
return $aVariablesResults;
}

View File

@@ -2084,7 +2084,9 @@ SQL;
}
// Remove any remaining nulls (for positions that weren't referenced)
$aReplacements = array_filter($aReplacements, static function ($val) { return $val !== null; });
$aReplacements = array_filter($aReplacements, static function ($val) {
return $val !== null;
});
} else {
// For non-positional, we need to map each position
$aReplacements = [];

View File

@@ -4,7 +4,7 @@
"type": "project",
"license": "AGPL-3.0-only",
"require": {
"php": ">=8.1.0 <8.4.0",
"php": ">=8.1.0 <8.5.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -12,8 +12,7 @@
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"apereo/phpcas": "~1.6.0",
"firebase/php-jwt": "^6.4.0",
"apereo/phpcas": "dev-master",
"guzzlehttp/guzzle": "^7.5.1",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "dev-master",
@@ -40,10 +39,16 @@
"symfony/stopwatch": "~6.4.0",
"symfony/web-profiler-bundle": "~6.4.0"
},
"repositories": [{
"type": "vcs",
"url": "https://github.com/Combodo/PHP-Parser"
}],
"repositories": [
{
"type": "vcs",
"url": "https://github.com/Combodo/PHP-Parser"
},
{
"type": "vcs",
"url": "https://github.com/EsupPortail/phpCAS"
}
],
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",

364
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -928,7 +928,7 @@ class Config
'type' => 'string',
'description' => 'Actions that are available as direct buttons next to the "Actions" menu',
// examples... not used
'default' => 'UI:Menu:Modify,UI:Menu:New',
'default' => 'UI:Menu:Modify,UI:Menu:New,UI:Menu:impacts_down,UI:Menu:impacts_up',
'value' => 'UI:Menu:Modify',
'source_of_value' => '',
'show_in_conf_sample' => true,

View File

@@ -5,6 +5,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
@@ -13,7 +14,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
@@ -55,6 +55,8 @@ class CSVBulkExport extends TabularBulkExport
$this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data'));
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
$sDateFormatRadio = utils::ReadParam('csv_date_format_radio', '');
switch ($sDateFormatRadio) {
case 'default':
@@ -223,6 +225,10 @@ class CSVBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom);
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
$oP->add_ready_script(
<<<EOF
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
@@ -264,6 +270,13 @@ EOF
default:
$sRet = trim($oObj->GetAsCSV($sAttCode), '"');
}
// If the option to ignore Excel sanitization is not set or explicitly set to false, apply sanitization
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
return ExportHelper::SanitizeField($sRet, $this->aStatusInfo['text_qualifier'] ?? '');
}
// The option to ignore Excel sanitization is explicitly set to true: return the raw value without sanitization
return $sRet;
}
@@ -337,6 +350,12 @@ EOF
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']);
}
}
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
$sField = ExportHelper::SanitizeField($sField, $this->aStatusInfo['text_qualifier']);
}
if ($this->aStatusInfo['charset'] != 'UTF-8') {
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket N°991)

View File

@@ -5,13 +5,13 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
@@ -63,6 +63,8 @@ class ExcelBulkExport extends TabularBulkExport
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data');
}
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
}
public function EnumFormParts()
@@ -121,6 +123,10 @@ class ExcelBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom);
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
$oP->add_ready_script(
<<<EOF
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
@@ -216,6 +222,12 @@ EOF
}
}
}
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
return ExportHelper::SanitizeField($sRet, '');
}
return $sRet;
}

View File

@@ -4,3 +4,4 @@
*/
@import "bulk-modify";
@import "bulk-export";

View File

@@ -0,0 +1,10 @@
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked), #form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked){
#ibo-sanitize-excel-export--alert {
display: none;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
@@ -8,5 +9,4 @@ namespace Combodo\iTop\DBTools\Exception;
class AuthenticationException extends \Exception
{
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1528,6 +1528,12 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
// Add translation for Fieldsets
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Obecné informace',
'Server:Date' => 'Data',
'Server:moreinfo' => 'Více informací',

View File

@@ -1527,6 +1527,12 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
// Add translation for Fieldsets
Dict::Add('DA DA', 'Danish', 'Dansk', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Almindelig Informationen',
'Server:Date' => 'Dato',
'Server:moreinfo' => 'Yderligere Information',

View File

@@ -1527,6 +1527,12 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
// Add translation for Fieldsets
Dict::Add('DE DE', 'German', 'Deutsch', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Allgemeine Informationen',
'Server:Date' => 'Datum',
'Server:moreinfo' => 'Weitere Informationen',

View File

@@ -57,26 +57,7 @@ Dict::Add('EN US', 'English', 'English', [
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
// Class:<class_name>/UniquenessRule:<rule_code>
// Class:<class_name>/UniquenessRule:<rule_code>+
//////////////////////////////////////////////////////////////////////
// Note: The classes have been grouped by categories: bizmodel
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
//
@@ -1535,6 +1516,17 @@ Dict::Add('EN US', 'English', 'English', [
'Class:Group/Attribute:parent_id_friendlyname+' => '',
]);
//
// Class: PhysicalInterface
//
Dict::Add('EN US', 'English', 'English', [
'Class:PhysicalInterface/Attribute:org_id' => 'Org id',
'Class:PhysicalInterface/Attribute:org_id+' => '',
'Class:PhysicalInterface/Attribute:location_id' => 'Location id',
'Class:PhysicalInterface/Attribute:location_id+' => '',
]);
//
// Class: lnkGroupToCI
//
@@ -1555,23 +1547,6 @@ Dict::Add('EN US', 'English', 'English', [
'Class:lnkGroupToCI/Attribute:reason+' => '',
]);
// Add translation for Fieldsets
Dict::Add('EN US', 'English', 'English', [
'Server:baseinfo' => 'General information',
'Server:Date' => 'Dates',
'Server:moreinfo' => 'More information',
'Server:otherinfo' => 'Other information',
'Server:power' => 'Power supply',
'Class:Subnet/Tab:IPUsage' => 'IP Usage',
'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not',
'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces having an IP in the range: <em>%1$s</em> to <em>%2$s</em>',
'Class:Subnet/Tab:FreeIPs' => 'Free IPs',
'Class:Subnet/Tab:FreeIPs-count' => 'Free IPs: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => 'Here is an extract of 10 free IP addresses',
'Class:Document:PreviewTab' => 'Preview',
]);
//
// Class: lnkDocumentToFunctionalCI
//
@@ -1590,6 +1565,29 @@ Dict::Add('EN US', 'English', 'English', [
'Class:lnkDocumentToFunctionalCI/Attribute:document_name+' => '',
]);
// Add translation for Fieldsets
Dict::Add('EN US', 'English', 'English', [
'ConfigMgnt:baseinfo' => 'General',
'ConfigMgnt:moreinfo' => 'CI specifics',
'ConfigMgnt:otherinfo' => 'Dates and description',
'Storage:moreinfo' => 'Storage specifics',
'Software:moreinfo' => 'Software specifics',
'Phone:moreinfo' => 'Phone specifics',
'Server:baseinfo' => 'General',
'Server:moreinfo' => 'Device specifics',
'Server:Date' => 'Dates',
'Server:otherinfo' => 'Description',
'Server:power' => 'Power supply',
'Class:Subnet/Tab:IPUsage' => 'IP Usage',
'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not',
'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces having an IP in the range: <em>%1$s</em> to <em>%2$s</em>',
'Class:Subnet/Tab:FreeIPs' => 'Free IPs',
'Class:Subnet/Tab:FreeIPs-count' => 'Free IPs: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => 'Here is an extract of 10 free IP addresses',
'Class:Document:PreviewTab' => 'Preview',
]);
//
// Application Menu
//
@@ -1640,14 +1638,3 @@ Dict::Add('EN US', 'English', 'English', [
'Menu:Software' => 'Software catalog',
'Menu:Software+' => 'Software catalog',
]);
//
// Class: PhysicalInterface
//
Dict::Add('EN US', 'English', 'English', [
'Class:PhysicalInterface/Attribute:org_id' => 'Org id',
'Class:PhysicalInterface/Attribute:org_id+' => '',
'Class:PhysicalInterface/Attribute:location_id' => 'Location id',
'Class:PhysicalInterface/Attribute:location_id+' => '',
]);

View File

@@ -59,26 +59,6 @@ Dict::Add('EN GB', 'British English', 'British English', [
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
// Class:<class_name>/UniquenessRule:<rule_code>
// Class:<class_name>/UniquenessRule:<rule_code>+
//////////////////////////////////////////////////////////////////////
// Note: The classes have been grouped by categories: bizmodel
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
//
// Class: lnkContactToFunctionalCI
//
@@ -1548,10 +1528,16 @@ Dict::Add('EN GB', 'British English', 'British English', [
// Add translation for Fieldsets
Dict::Add('EN GB', 'British English', 'British English', [
'Server:baseinfo' => 'General information',
'ConfigMgnt:baseinfo' => 'General',
'ConfigMgnt:moreinfo' => 'CI specifics',
'ConfigMgnt:otherinfo' => 'Dates and description',
'Storage:moreinfo' => 'Storage specifics',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'General',
'Server:moreinfo' => 'Device specifics',
'Server:Date' => 'Dates',
'Server:moreinfo' => 'More information',
'Server:otherinfo' => 'Other information',
'Server:otherinfo' => 'Description',
'Server:power' => 'Power supply',
'Class:Subnet/Tab:IPUsage' => 'IP Usage',
'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not',

View File

@@ -1524,6 +1524,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
// Add translation for Fieldsets
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Información General',
'Server:Date' => 'Fecha',
'Server:moreinfo' => 'Más Información',

View File

@@ -36,23 +36,6 @@ Dict::Add('FR FR', 'French', 'Français', [
// Class:<class_name>/UniquenessRule:<rule_code>
// Class:<class_name>/UniquenessRule:<rule_code>+
//////////////////////////////////////////////////////////////////////
// Classes in 'bizmodel'
//////////////////////////////////////////////////////////////////////
//
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
// Class:<class_name>/UniquenessRule:<rule_code>
// Class:<class_name>/UniquenessRule:<rule_code>+
//////////////////////////////////////////////////////////////////////
// Note: The classes have been grouped by categories: bizmodel
//////////////////////////////////////////////////////////////////////
@@ -1685,6 +1668,17 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Group/Attribute:parent_id_friendlyname+' => '',
]);
//
// Class: PhysicalInterface
//
Dict::Add('FR FR', 'French', 'Français', [
'Class:PhysicalInterface/Attribute:org_id' => 'Organisation',
'Class:PhysicalInterface/Attribute:org_id+' => '',
'Class:PhysicalInterface/Attribute:location_id' => 'Site',
'Class:PhysicalInterface/Attribute:location_id+' => '',
]);
//
// Class: lnkGroupToCI
//
@@ -1705,23 +1699,6 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:lnkGroupToCI/Attribute:reason+' => '',
]);
// Add translation for Fieldsets
Dict::Add('FR FR', 'French', 'Français', [
'Server:baseinfo' => 'Informations générales',
'Server:Date' => 'Dates',
'Server:moreinfo' => 'Informations complémentaires',
'Server:otherinfo' => 'Autres informations',
'Server:power' => 'Alimentation électrique',
'Class:Subnet/Tab:IPUsage' => 'IP utilisées',
'Class:Subnet/Tab:IPUsage+' => 'Utilisation des IPs de ce subnet',
'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces ayant une IP dans la plage: <em>%1$s</em> à <em>%2$s</em>',
'Class:Subnet/Tab:FreeIPs' => 'IP disponibles',
'Class:Subnet/Tab:FreeIPs-count' => 'IP disponibles: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => 'Voici un échantillon de dix addresses IP disponibles',
'Class:Document:PreviewTab' => 'Aperçu',
]);
//
// Class: lnkDocumentToFunctionalCI
//
@@ -1740,6 +1717,29 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:lnkDocumentToFunctionalCI/Attribute:document_name+' => '',
]);
// Add translation for Fieldsets
Dict::Add('FR FR', 'French', 'Français', [
'ConfigMgnt:baseinfo' => 'Informations générales',
'Server:baseinfo' => 'Informations générales',
'ConfigMgnt:moreinfo' => 'Item spécifique',
'Server:moreinfo' => 'Matériel spécifique',
'Storage:moreinfo' => 'Stockage spécifique',
'Software:moreinfo' => 'Logiciel spécifique',
'Phone:moreinfo' => 'Téléphone spécifique',
'ConfigMgnt:otherinfo' => 'Dates et description',
'Server:Date' => 'Dates',
'Server:otherinfo' => 'Description',
'Server:power' => 'Alimentation électrique',
'Class:Subnet/Tab:IPUsage' => 'IP utilisées',
'Class:Subnet/Tab:IPUsage+' => 'Utilisation des IPs de ce subnet',
'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces ayant une IP dans la plage: <em>%1$s</em> à <em>%2$s</em>',
'Class:Subnet/Tab:FreeIPs' => 'IP disponibles',
'Class:Subnet/Tab:FreeIPs-count' => 'IP disponibles: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => 'Voici un échantillon de dix addresses IP disponibles',
'Class:Document:PreviewTab' => 'Aperçu',
]);
//
// Application Menu
//
@@ -1790,14 +1790,3 @@ Dict::Add('FR FR', 'French', 'Français', [
'Menu:Software' => 'Catalogue des logiciels de références',
'Menu:Software+' => 'Catalogue des logiciels de références',
]);
//
// Class: PhysicalInterface
//
Dict::Add('FR FR', 'French', 'Français', [
'Class:PhysicalInterface/Attribute:org_id' => 'Organisation',
'Class:PhysicalInterface/Attribute:org_id+' => '',
'Class:PhysicalInterface/Attribute:location_id' => 'Site',
'Class:PhysicalInterface/Attribute:location_id+' => '',
]);

View File

@@ -1526,10 +1526,16 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
// Add translation for Fieldsets
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Általános információ',
'Server:Date' => 'Dátumok',
'Server:moreinfo' => 'További információ',
'Server:otherinfo' => 'Other information~~',
'Server:otherinfo' => 'Description~~',
'Server:power' => 'Áramforrás',
'Class:Subnet/Tab:IPUsage' => 'IP felhasználás',
'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not~~',

View File

@@ -1547,6 +1547,12 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
// Add translation for Fieldsets
Dict::Add('IT IT', 'Italian', 'Italiano', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Informazioni generali',
'Server:Date' => 'Date',
'Server:moreinfo' => 'Ulteriori informazioni',

View File

@@ -1526,6 +1526,12 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
// Add translation for Fieldsets
Dict::Add('JA JP', 'Japanese', '日本語', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => '基本情報',
'Server:Date' => '日付',
'Server:moreinfo' => '追加情報',

View File

@@ -1528,6 +1528,12 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
// Add translation for Fieldsets
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Globale informatie',
'Server:Date' => 'Datum',
'Server:moreinfo' => 'Meer informatie',

View File

@@ -1526,6 +1526,12 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
// Add translation for Fieldsets
Dict::Add('PL PL', 'Polish', 'Polski', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Informacje ogólne',
'Server:Date' => 'Daty',
'Server:moreinfo' => 'Więcej informacji',

View File

@@ -1526,6 +1526,12 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
// Add translation for Fieldsets
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Informações gerais',
'Server:Date' => 'Data',
'Server:moreinfo' => 'Mais informações',

View File

@@ -1527,6 +1527,12 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
// Add translation for Fieldsets
Dict::Add('RU RU', 'Russian', 'Русский', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Основное',
'Server:Date' => 'Даты',
'Server:moreinfo' => 'Спецификация',

View File

@@ -1526,6 +1526,12 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
// Add translation for Fieldsets
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Všeobecné informácie',
'Server:Date' => 'Dátum',
'Server:moreinfo' => 'Viac informácií',

View File

@@ -1527,6 +1527,12 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
// Add translation for Fieldsets
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => 'Genel Bilgi',
'Server:Date' => 'Tarihler',
'Server:moreinfo' => 'Daha fazla bilgi',

View File

@@ -1543,6 +1543,12 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
// Add translation for Fieldsets
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'ConfigMgnt:baseinfo' => 'General~~',
'ConfigMgnt:moreinfo' => 'CI specifics~~',
'Storage:moreinfo' => 'Storage specifics~~',
'ConfigMgnt:otherinfo' => 'Dates and description~~',
'Software:moreinfo' => 'Software specifics~~',
'Phone:moreinfo' => 'Phone specifics~~',
'Server:baseinfo' => '基本信息',
'Server:Date' => '日期',
'Server:moreinfo' => '更多信息',

View File

@@ -228,6 +228,10 @@
<attribute id="containervirtualhost_id_friendlyname"/>
</complementary_attributes>
</naming>
<fields_semantic>
<state_attribute>status</state_attribute>
<image_attribute>logo</image_attribute>
</fields_semantic>
<reconciliation>
<attributes>
<attribute id="name"/>
@@ -235,9 +239,6 @@
<attribute id="finalclass"/>
</attributes>
</reconciliation>
<fields_semantic>
<state_attribute>status</state_attribute>
</fields_semantic>
<style>
<icon>images/icons8-application-container.svg</icon>
</style>
@@ -255,6 +256,13 @@
<on_target_delete>DEL_AUTO</on_target_delete>
<tracking_level>all</tracking_level>
</field>
<field id="logo" xsi:type="AttributeImage">
<display_max_width>96</display_max_width>
<display_max_height>96</display_max_height>
<storage_max_width>128</storage_max_width>
<storage_max_height>128</storage_max_height>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="containerimages_list" xsi:type="AttributeLinkedSetIndirect">
<linked_class>lnkContainerApplicationToImage</linked_class>
<ext_key_to_me>containerapplication_id</ext_key_to_me>
@@ -357,9 +365,12 @@
<item id="move2production">
<rank>50</rank>
</item>
<item id="description">
<item id="logo">
<rank>60</rank>
</item>
<item id="description">
<rank>70</rank>
</item>
</items>
<rank>10</rank>
</item>

View File

@@ -57,47 +57,77 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="nb_u">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="nb_u">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
<item id="move2production">
<rank>110</rank>
</item>
<item id="purchase_date">
<rank>120</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
<item id="description">
<rank>140</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>110</rank>
</item>
<item id="purchase_date">
<rank>120</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>140</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>150</rank>
@@ -257,50 +287,80 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="rack_id">
<rank>60</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>70</rank>
</item>
<item id="model_id">
<rank>80</rank>
</item>
<item id="nb_u">
<rank>90</rank>
</item>
<item id="serialnumber">
<rank>100</rank>
</item>
<item id="asset_number">
<rank>110</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="rack_id">
<rank>60</rank>
</item>
<item id="brand_id">
<rank>70</rank>
</item>
<item id="model_id">
<rank>80</rank>
</item>
<item id="nb_u">
<rank>90</rank>
</item>
<item id="serialnumber">
<rank>100</rank>
</item>
<item id="asset_number">
<rank>110</rank>
</item>
<item id="move2production">
<rank>120</rank>
</item>
<item id="purchase_date">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>140</rank>
</item>
<item id="description">
<rank>150</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>120</rank>
</item>
<item id="purchase_date">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>140</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>150</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>160</rank>
@@ -440,44 +500,74 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
<item id="description">
<rank>130</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>130</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>140</rank>
@@ -613,44 +703,74 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
<item id="description">
<rank>130</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>130</rank>
</item>
</items>
</item>
</items>
</item>
<item id="pdus_list">
<rank>140</rank>
@@ -806,50 +926,80 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="rack_id">
<rank>60</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="powerstart_id">
<rank>70</rank>
</item>
<item id="brand_id">
<rank>80</rank>
</item>
<item id="model_id">
<rank>90</rank>
</item>
<item id="serialnumber">
<rank>100</rank>
</item>
<item id="asset_number">
<rank>110</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="rack_id">
<rank>60</rank>
</item>
<item id="powerstart_id">
<rank>70</rank>
</item>
<item id="brand_id">
<rank>80</rank>
</item>
<item id="model_id">
<rank>90</rank>
</item>
<item id="serialnumber">
<rank>100</rank>
</item>
<item id="asset_number">
<rank>110</rank>
</item>
<item id="move2production">
<rank>120</rank>
</item>
<item id="purchase_date">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>140</rank>
</item>
<item id="description">
<rank>150</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>120</rank>
</item>
<item id="purchase_date">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>140</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>150</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>160</rank>

View File

@@ -193,47 +193,77 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Phone:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
<item id="move2production">
<rank>110</rank>
</item>
<item id="purchase_date">
<rank>120</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
<item id="description">
<rank>140</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>110</rank>
</item>
<item id="purchase_date">
<rank>120</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>140</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>150</rank>
@@ -374,53 +404,83 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Phone:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="imei">
<rank>90</rank>
</item>
<item id="hw_pin">
<rank>100</rank>
</item>
<item id="serialnumber">
<rank>110</rank>
</item>
<item id="asset_number">
<rank>120</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="imei">
<rank>90</rank>
</item>
<item id="hw_pin">
<rank>100</rank>
</item>
<item id="serialnumber">
<rank>110</rank>
</item>
<item id="asset_number">
<rank>120</rank>
</item>
<item id="move2production">
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>130</rank>
</item>
<item id="purchase_date">
</item>
<item id="purchase_date">
<rank>140</rank>
</item>
<item id="end_of_warranty">
<rank>150</rank>
</item>
<item id="description">
<rank>160</rank>
</item>
<item id="end_of_warranty">
<rank>150</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>160</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>170</rank>
@@ -553,47 +613,77 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Phone:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="phonenumber">
<rank>80</rank>
</item>
<item id="serialnumber">
<rank>90</rank>
</item>
<item id="asset_number">
<rank>100</rank>
</item>
<item id="move2production">
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>110</rank>
</item>
<item id="purchase_date">
</item>
<item id="purchase_date">
<rank>120</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
<item id="description">
<rank>140</rank>
</item>
<item id="end_of_warranty">
<rank>130</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>140</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>150</rank>
@@ -722,44 +812,74 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
<item id="move2production">
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
<item id="description">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>130</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>140</rank>
@@ -938,23 +1058,8 @@
<presentation>
<details>
<items>
<item id="softwares_list">
<rank>5</rank>
</item>
<item id="contacts_list">
<rank>10</rank>
</item>
<item id="documents_list">
<rank>20</rank>
</item>
<item id="physicalinterface_list">
<rank>40</rank>
</item>
<item id="networkdevice_list">
<rank>50</rank>
</item>
<item id="col:col1">
<rank>80</rank>
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
@@ -1011,7 +1116,7 @@
</items>
</item>
<item id="col:col2">
<rank>90</rank>
<rank>20</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
@@ -1037,6 +1142,21 @@
</item>
</items>
</item>
<item id="softwares_list">
<rank>50</rank>
</item>
<item id="contacts_list">
<rank>80</rank>
</item>
<item id="documents_list">
<rank>90</rank>
</item>
<item id="physicalinterface_list">
<rank>100</rank>
</item>
<item id="networkdevice_list">
<rank>110</rank>
</item>
</items>
</details>
<search>
@@ -1159,20 +1279,8 @@
<presentation>
<details>
<items>
<item id="contacts_list">
<rank>10</rank>
</item>
<item id="documents_list">
<rank>20</rank>
</item>
<item id="physicalinterface_list">
<rank>40</rank>
</item>
<item id="networkdevice_list">
<rank>50</rank>
</item>
<item id="col:col1">
<rank>80</rank>
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
@@ -1214,7 +1322,7 @@
</items>
</item>
<item id="col:col2">
<rank>90</rank>
<rank>20</rank>
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
@@ -1240,6 +1348,18 @@
</item>
</items>
</item>
<item id="contacts_list">
<rank>80</rank>
</item>
<item id="documents_list">
<rank>90</rank>
</item>
<item id="physicalinterface_list">
<rank>100</rank>
</item>
<item id="networkdevice_list">
<rank>110</rank>
</item>
</items>
</details>
<search>
@@ -1359,44 +1479,74 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
</items>
</item>
</items>
</item>
<item id="org_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="status">
<rank>30</rank>
</item>
<item id="business_criticity">
<rank>40</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
<item id="brand_id">
<rank>60</rank>
</item>
<item id="model_id">
<rank>70</rank>
</item>
<item id="serialnumber">
<rank>80</rank>
</item>
<item id="asset_number">
<rank>90</rank>
</item>
<item id="move2production">
<items>
<item id="fieldset:Server:Date">
<rank>10</rank>
<items>
<item id="move2production">
<rank>100</rank>
</item>
<item id="purchase_date">
</item>
<item id="purchase_date">
<rank>110</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
<item id="description">
<rank>130</rank>
</item>
<item id="end_of_warranty">
<rank>120</rank>
</item>
</items>
</item>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>130</rank>
</item>
</items>
</item>
</items>
</item>
<item id="contacts_list">
<rank>140</rank>

View File

@@ -10,8 +10,6 @@ $ipb-progress--bar--border-radius: $ipb-progress--border-radius !default;
}
.ipb-progress--bar, .progress-bar {
background-color: $ipb-color-primary-600;
color: #ffffff;
line-height: $ipb-progress--bar--line-height;
border-radius: $ipb-progress--bar--border-radius;

View File

@@ -9,6 +9,6 @@ $ipb-progress--bar--color: $ipb-color-white-100 !default;
}
.ipb-progress--bar, .progress-bar {
background-color: $ipb-color-primary-700;
background-color: $ipb-progress--bar--background-color;
color: $ipb-progress--bar--color;
}

View File

@@ -11,7 +11,7 @@
</div>
<div id="export-feedback" class="ipb-export--feedback">
<p id="export-excel-warning" class="ipb-alert alert alert-warning" role="alert">{{ 'UI:Bulk:Export:MaliciousInjection:Alert:Message'|dict_format(sWikiUrl)|raw }}</p>
<p id="export-excel-warning" class="ipb-alert alert alert-warning" role="alert">{{ 'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message'|dict_format(sWikiUrl)|raw }}</p>
<div class="ipb-export--illustration ipb-svg-illustration--container">
{{ source('illustrations/undraw_export-files.svg') }}
</div>

View File

@@ -873,7 +873,7 @@
</item>
</items>
</item>
<item id="fieldset:Server:moreinfo">
<item id="fieldset:Storage:moreinfo">
<rank>20</rank>
<items>
<item id="brand_id">
@@ -1212,26 +1212,51 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Storage:moreinfo">
<rank>20</rank>
<items>
<item id="nas_id">
<rank>20</rank>
</item>
<item id="raid_level">
<rank>60</rank>
</item>
<item id="size">
<rank>70</rank>
</item>
</items>
</item>
</items>
</item>
<item id="nas_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="location_id">
<rank>30</rank>
</item>
<item id="org_id">
<rank>40</rank>
</item>
<item id="description">
<rank>50</rank>
</item>
<item id="raid_level">
<rank>60</rank>
</item>
<item id="size">
<rank>70</rank>
<items>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>10</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
@@ -1350,26 +1375,41 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
</item>
<item id="datacenterdevice_id">
<rank>20</rank>
</item>
<item id="location_id">
<rank>30</rank>
</item>
<item id="org_id">
<rank>40</rank>
</item>
<item id="speed">
<rank>50</rank>
</item>
<item id="topology">
<rank>60</rank>
</item>
<item id="wwn">
<rank>70</rank>
<items>
<item id="fieldset:Server:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Storage:moreinfo">
<rank>20</rank>
<items>
<item id="datacenterdevice_id">
<rank>20</rank>
</item>
<item id="speed">
<rank>50</rank>
</item>
<item id="topology">
<rank>60</rank>
</item>
<item id="wwn">
<rank>70</rank>
</item>
</items>
</item>
</items>
</item>
</items>
</details>
@@ -1521,29 +1561,54 @@
<presentation>
<details>
<items>
<item id="name">
<item id="col:col1">
<rank>10</rank>
<items>
<item id="fieldset:ConfigMgnt:baseinfo">
<rank>10</rank>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="location_id">
<rank>50</rank>
</item>
</items>
</item>
<item id="fieldset:Storage:moreinfo">
<rank>20</rank>
<items>
<item id="lun_id">
<rank>20</rank>
</item>
<item id="storagesystem_id">
<rank>30</rank>
</item>
<item id="raid_level">
<rank>70</rank>
</item>
<item id="size">
<rank>80</rank>
</item>
</items>
</item>
</items>
</item>
<item id="lun_id">
<item id="col:col2">
<rank>20</rank>
</item>
<item id="storagesystem_id">
<rank>30</rank>
</item>
<item id="location_id">
<rank>40</rank>
</item>
<item id="org_id">
<rank>50</rank>
</item>
<item id="description">
<rank>60</rank>
</item>
<item id="raid_level">
<rank>70</rank>
</item>
<item id="size">
<rank>80</rank>
<items>
<item id="fieldset:Server:otherinfo">
<rank>20</rank>
<items>
<item id="description">
<rank>10</rank>
</item>
</items>
</item>
</items>
</item>
<item id="servers_list">
<rank>90</rank>

View File

@@ -994,6 +994,9 @@
<attribute id="location_id_friendlyname"/>
</complementary_attributes>
</naming>
<fields_semantic>
<image_attribute>logo</image_attribute>
</fields_semantic>
<reconciliation>
<attributes>
<attribute id="name"/>
@@ -1003,7 +1006,7 @@
</attributes>
</reconciliation>
<style>
<icon>images/icons8-cloud.svg</icon>
<icon>../../images/icons/icons8-cloud.svg</icon>
</style>
</properties>
<fields>
@@ -1026,6 +1029,13 @@
<on_target_delete>DEL_MANUAL</on_target_delete>
<tracking_level>all</tracking_level>
</field>
<field id="logo" xsi:type="AttributeImage">
<display_max_width>96</display_max_width>
<display_max_height>96</display_max_height>
<storage_max_width>128</storage_max_width>
<storage_max_height>128</storage_max_height>
<is_null_allowed>true</is_null_allowed>
</field>
</fields>
<methods/>
<presentation>
@@ -1106,9 +1116,12 @@
<item id="move2production">
<rank>50</rank>
</item>
<item id="description">
<item id="logo">
<rank>60</rank>
</item>
<item id="description">
<rank>70</rank>
</item>
</items>
<rank>10</rank>
</item>

View File

@@ -13,5 +13,9 @@
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('DA DA', 'Danish', 'Dansk', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('DE DE', 'German', 'Deutsch', [
'UI:Bulk:modify:IncompatibleAttribute' => 'Dieses Attribut kann in einer Massenänderung nicht bearbeitet werden.',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel-Sicherheitswarnung',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Das Öffnen einer Datei mit nicht vertrauenswürdigen Daten in Microsoft Excel kann zu einer Formel-Injektion führen. Stellen Sie sicher, dass Ihre Excel-Einstellungen so konfiguriert sind, dass Dateien sicher verarbeitet werden. <a href="%1$s">Erfahren Sie mehr in unserer Dokumentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Das Öffnen einer Datei mit nicht vertrauenswürdigen Daten in Microsoft Excel kann zu einer Formel-Injektion führen. Stellen Sie sicher, dass Ihre Excel-Einstellungen so konfiguriert sind, dass Dateien sicher verarbeitet werden. <a href="%1$s" target="_blank">Erfahren Sie mehr in unserer Dokumentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -23,5 +23,9 @@ Dict::Add('EN US', 'English', 'English', [
// Bulk modify
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.',
'Core:BulkExport:Security' => 'Security',
]);

View File

@@ -10,5 +10,9 @@ Dict::Add('EN GB', 'British English', 'British English', [
// Bulk modify
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.',
'Core:BulkExport:Security' => 'Security',
]);

View File

@@ -11,5 +11,9 @@
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'UI:Bulk:modify:IncompatibleAttribute' => 'Este atributo no se puede editar en contexto masivo',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Advertencia de seguridad de Excel',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Abrir un archivo con datos que no son de confianza en Microsoft Excel puede provocar la inyección de fórmulas. Asegúrese de que la configuración de Excel esté configurada para manejar archivos de forma segura. <a href="%1$s">Obtenga más información en nuestra documentación.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Abrir un archivo con datos que no son de confianza en Microsoft Excel puede provocar la inyección de fórmulas. Asegúrese de que la configuración de Excel esté configurada para manejar archivos de forma segura. <a href="%1$s" target="_blank">Obtenga más información en nuestra documentación.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('FR FR', 'French', 'Français', [
'UI:Bulk:modify:IncompatibleAttribute' => 'Cet attribut ne peut être édité dans une modification en masse',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Avertissement sur la sécurité d\'Excel',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'ouverture d\'un fichier contenant des données non fiables dans Microsoft Excel peut entraîner l\'injection de formules. Assurez-vous que vos paramètres Excel sont configurés pour traiter les fichiers en toute sécurité. <a href="%1$s">Pour en savoir plus, consultez notre documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'ouverture d\'un fichier contenant des données non fiables dans Microsoft Excel peut entraîner l\'injection de formules. Assurez-vous que vos paramètres Excel sont configurés pour traiter les fichiers en toute sécurité. <a href="%1$s" target="_blank">Pour en savoir plus, consultez notre documentation.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Certaines valeurs ont été échappées pour prévenir de potentielles failles de sécurités dans Microsoft Excel. <a href="%1$s" target="_blank">Pour en savoir plus, consultez notre documentation</a>',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitiser les valeurs potentiellement dangereuses',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'Lorsqu\'elle est activée, les valeurs potentiellement dangereuses seront sanitizées lors de l\'exportation. Cela empêchera Microsoft Excel de les interpréter comme des formules. Notez que cela peut altérer les données originales en les préfixant avec une simple quote (\') pour s\'assurer qu\'elles soient traitées comme du texte.',
'Core:BulkExport:Security' => 'Sécurité',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('IT IT', 'Italian', 'Italiano', [
'UI:Bulk:modify:IncompatibleAttribute' => 'Questo attributo non può essere modificato nel contesto di modifica bulk',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Avviso di sicurezza di Excel',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'apertura di un file con dati non fidati in Microsoft Excel potrebbe comportare l\'iniezione di formule. Assicurati che le impostazioni di Excel siano configurate per gestire i file in modo sicuro. <a href="%1$s">Ulteriori informazioni nella nostra documentazione.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'apertura di un file con dati non fidati in Microsoft Excel potrebbe comportare l\'iniezione di formule. Assicurati che le impostazioni di Excel siano configurate per gestire i file in modo sicuro. <a href="%1$s" target="_blank">Ulteriori informazioni nella nostra documentazione.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('JA JP', 'Japanese', '日本語', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('PL PL', 'Polish', 'Polski', [
'UI:Bulk:modify:IncompatibleAttribute' => 'Tego atrybutu nie można edytować zbiorczo',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Ostrzeżenie dotyczące bezpieczeństwa programu Excel',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Otwarcie pliku z niezaufanymi danymi w programie Microsoft Excel może spowodować wstrzyknięcie formuły. Upewnij się, że ustawienia programu Excel są skonfigurowane tak, aby bezpiecznie obsługiwać pliki. <a href="%1$s">Dowiedz się więcej w naszej dokumentacji.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Otwarcie pliku z niezaufanymi danymi w programie Microsoft Excel może spowodować wstrzyknięcie formuły. Upewnij się, że ustawienia programu Excel są skonfigurowane tak, aby bezpiecznie obsługiwać pliki. <a href="%1$s" target="_blank">Dowiedz się więcej w naszej dokumentacji.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('RU RU', 'Russian', 'Русский', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -13,5 +13,9 @@
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

@@ -22,5 +22,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
// Bulk modify
'UI:Bulk:modify:IncompatibleAttribute' => '此属性无法在批量操作中编辑',
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel 安全警告',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => '在 Microsoft Excel 中打开不信任的文件可能导致公式注入. 请确保 Excel 设置能够安全的处理该文件. <a href="%1$s">进入我们的文档了解更多.</a>',
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => '在 Microsoft Excel 中打开不信任的文件可能导致公式注入. 请确保 Excel 设置能够安全的处理该文件. <a href="%1$s" target="_blank">进入我们的文档了解更多.</a>',
'UI:Bulk:Export:MaliciousInjection:Sanitization:Alert:Message' => 'Some values have been sanitized to prevent potential security issues in Microsoft Excel. <a href="%1$s" target="_blank">Learn more in our documentation.</a>~~',
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
'Core:BulkExport:Security' => 'Security~~',
]);

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -402,6 +402,12 @@ function ExportStartExport() {
oParams.expression = $('#export-form :input[name=expression]').val();
oParams.query = $('#export-form :input[name=query]').val();
}
// Read the "sanitize_excel_export" checkbox if it exists, and set the corresponding "ignore_excel_sanitization" parameter
if($(':input[name=sanitize_excel_export]').length > 0) {
oParams.ignore_excel_sanitization = $(':input[name=sanitize_excel_export]').is(':checked') ? 0 : 1;
}
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function (data) {
if (data == null) {
ExportError('Export failed (no data provided), please contact your administrator');

View File

@@ -13,7 +13,7 @@ Api documentation can be found here:
https://apereo.github.io/phpCAS/api/
[![Test](https://github.com/apereo/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/apereo/phpCAS/actions/workflows/test.yml)
[![Test](https://github.com/EsupPortail/phpCAS/actions/workflows/test.yml/badge.svg)](https://github.com/EsupPortail/phpCAS/actions/workflows/test.yml)
LICENSE
-------

View File

@@ -57,7 +57,7 @@ if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($
/**
* phpCAS version. accessible for the user by phpCAS::getVersion().
*/
define('PHPCAS_VERSION', '1.6.1');
define('PHPCAS_VERSION', '1.6.1+');
/**
* @addtogroup public
@@ -303,7 +303,7 @@ class phpCAS
/**
* This variable is used to enable verbose mode
* This pevents debug info to be show to the user. Since it's a security
* This prevents debug info to be show to the user. Since it's a security
* feature the default is false
*
* @hideinitializer
@@ -338,7 +338,7 @@ class phpCAS
* @param bool $changeSessionID Allow phpCAS to change the session_id
* (Single Sign Out/handleLogoutRequests
* is based on that change)
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return void a newly created CAS_Client object
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
@@ -347,7 +347,7 @@ class phpCAS
*/
public static function client($server_version, $server_hostname,
$server_port, $server_uri, $service_base_url,
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
$changeSessionID = true, ?\SessionHandlerInterface $sessionHandler = null
) {
phpCAS :: traceBegin();
if (is_object(self::$_PHPCAS_CLIENT)) {
@@ -393,7 +393,7 @@ class phpCAS
* @param bool $changeSessionID Allow phpCAS to change the session_id
* (Single Sign Out/handleLogoutRequests
* is based on that change)
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return void a newly created CAS_Client object
* @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
@@ -402,14 +402,14 @@ class phpCAS
*/
public static function proxy($server_version, $server_hostname,
$server_port, $server_uri, $service_base_url,
$changeSessionID = true, \SessionHandlerInterface $sessionHandler = null
$changeSessionID = true, ?\SessionHandlerInterface $sessionHandler = null
) {
phpCAS :: traceBegin();
if (is_object(self::$_PHPCAS_CLIENT)) {
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
}
// store where the initialzer is called from
// store where the initializer is called from
$dbg = debug_backtrace();
self::$_PHPCAS_INIT_CALL = array (
'done' => true,
@@ -560,7 +560,7 @@ class phpCAS
$indent_str .= '| ';
}
// allow for multiline output with proper identing. Usefull for
// allow for multiline output with proper identing. Useful for
// dumping cas answers etc.
$str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
$str3 = self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2;
@@ -568,7 +568,7 @@ class phpCAS
self::$_PHPCAS_DEBUG['logger']->info($str3);
}
if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
// Check if file exists and modifiy file permissions to be only
// Check if file exists and modify file permissions to be only
// readable by the webserver
if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
touch(self::$_PHPCAS_DEBUG['filename']);
@@ -1769,7 +1769,7 @@ class phpCAS
/**
* If you want your service to be proxied you have to enable it (default
* disabled) and define an accepable list of proxies that are allowed to
* disabled) and define an acceptable list of proxies that are allowed to
* proxy your service.
*
* Add each allowed proxy definition object. For the normal CAS_ProxyChain
@@ -1790,7 +1790,7 @@ class phpCAS
* 'http://client.example.com/'
* )));
*
* For quick testing or in certain production screnarios you might want to
* For quick testing or in certain production scenarios you might want to
* allow allow any other valid service to proxy your service. To do so, add
* the "Any" chain:
* phpCAS::allowProxyChain(new CAS_ProxyChain_Any);
@@ -1897,7 +1897,7 @@ class phpCAS
}
/**
* Checks of a proxy client aready exists
* Checks of a proxy client already exists
*
* @throws CAS_OutOfSequenceBeforeProxyException
*

View File

@@ -788,7 +788,7 @@ class CAS_Client
'file' => $dbg[1]['file'],
'line' => $dbg[1]['line'],
'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
'result' => (boolean)$auth
'result' => (bool)$auth
);
}
private $_authentication_caller;
@@ -926,7 +926,7 @@ class CAS_Client
* CAS_ServiceBaseUrl_Interface for custom
* behavior. Added in 1.6.0. Similar to
* serverName config in other CAS clients.
* @param \SessionHandlerInterface $sessionHandler the session handler
* @param \SessionHandlerInterface|null $sessionHandler the session handler
*
* @return self a newly created CAS_Client object
*/
@@ -938,7 +938,7 @@ class CAS_Client
$server_uri,
$service_base_url,
$changeSessionID = true,
\SessionHandlerInterface $sessionHandler = null
?\SessionHandlerInterface $sessionHandler = null
) {
// Argument validation
if (gettype($server_version) != 'string')
@@ -3166,7 +3166,7 @@ class CAS_Client
$proxiedService->setCasClient($this);
}
return $proxiedService;
case PHPCAS_PROXIED_SERVICE_IMAP;
case PHPCAS_PROXIED_SERVICE_IMAP:
$proxiedService = new CAS_ProxiedService_Imap($this->_getUser());
if ($proxiedService instanceof CAS_ProxiedService_Testable) {
$proxiedService->setCasClient($this);

View File

@@ -316,7 +316,7 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
try {
$pdo->beginTransaction();
$query = $pdo->query($this->createTableSQL());
$query = $pdo->query($this->createTableSql());
$query->closeCursor();
$pdo->commit();

View File

@@ -127,6 +127,12 @@ class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage
if (!preg_match('`^[a-zA-Z]:`', $path)) {
phpCAS::error('an absolute path is needed for PGT storage to file');
}
// ensure that the directory separator on Windows is '/' for consistency with the rest of the phpcas code
$path = str_replace(DIRECTORY_SEPARATOR , '/', $path);
// store the path (with a trailing '/')
$path = preg_replace('|([^/])$|', '$1/', $path);
} else {

View File

@@ -139,7 +139,12 @@ implements CAS_Request_MultiRequestInterface
$buf = curl_multi_getcontent($handles[$i]);
$request->_storeResponseBody($buf);
curl_multi_remove_handle($multiHandle, $handles[$i]);
curl_close($handles[$i]);
if (PHP_VERSION_ID < 80000) {
curl_close($handles[$i]);
} else {
// unreference it => it will be closed
unset($handles[$i]);
}
}
curl_multi_close($multiHandle);

View File

@@ -86,7 +86,9 @@ implements CAS_Request_RequestInterface
}
// close the CURL session
curl_close($ch);
if (PHP_VERSION_ID < 80000) {
curl_close($ch);
}
phpCAS::traceEnd($res);
return $res;

View File

@@ -19,4 +19,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f::getLoader();
return ComposerAutoloaderInitfc0e9e9dea11dcbb6272414776c30685::getLoader();

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/patch-type-declarations
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/var-dump-server
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

View File

@@ -1,5 +0,0 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/yaml-lint
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

View File

@@ -1112,6 +1112,8 @@ return array(
'PhpParser\\ErrorHandler' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php',
'PhpParser\\ErrorHandler\\Collecting' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php',
'PhpParser\\ErrorHandler\\Throwing' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php',
'PhpParser\\ExprEvaluationException' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ExprEvaluationException.php',
'PhpParser\\ExprEvaluator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ExprEvaluator.php',
'PhpParser\\Internal\\DiffElem' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php',
'PhpParser\\Internal\\Differ' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php',
'PhpParser\\Internal\\PrintableNewAnonClassNode' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php',
@@ -2647,6 +2649,17 @@ return array(
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface' => $vendorDir . '/symfony/http-foundation/Session/Storage/SessionStorageInterface.php',
'Symfony\\Component\\HttpFoundation\\StreamedJsonResponse' => $vendorDir . '/symfony/http-foundation/StreamedJsonResponse.php',
'Symfony\\Component\\HttpFoundation\\StreamedResponse' => $vendorDir . '/symfony/http-foundation/StreamedResponse.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\RequestAttributeValueSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseCookieValueSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseFormatSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHasCookie' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHasHeader' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHeaderLocationSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHeaderSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsRedirected' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsSuccessful' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsUnprocessable' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseStatusCodeSame' => $vendorDir . '/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php',
'Symfony\\Component\\HttpFoundation\\UriSigner' => $vendorDir . '/symfony/http-foundation/UriSigner.php',
'Symfony\\Component\\HttpFoundation\\UrlHelper' => $vendorDir . '/symfony/http-foundation/UrlHelper.php',
'Symfony\\Component\\HttpKernel\\Attribute\\AsController' => $vendorDir . '/symfony/http-kernel/Attribute/AsController.php',

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f
class ComposerAutoloaderInitfc0e9e9dea11dcbb6272414776c30685
{
private static $loader;
@@ -24,21 +24,21 @@ class ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInitfc0e9e9dea11dcbb6272414776c30685', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit7f81b4a2a468a061c306af5e447a9a9f', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInitfc0e9e9dea11dcbb6272414776c30685', 'loadClassLoader'));
$includePaths = require __DIR__ . '/include_paths.php';
$includePaths[] = get_include_path();
set_include_path(implode(PATH_SEPARATOR, $includePaths));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
{
public static $files = array (
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
@@ -1498,6 +1498,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'PhpParser\\ErrorHandler' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php',
'PhpParser\\ErrorHandler\\Collecting' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php',
'PhpParser\\ErrorHandler\\Throwing' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php',
'PhpParser\\ExprEvaluationException' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ExprEvaluationException.php',
'PhpParser\\ExprEvaluator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ExprEvaluator.php',
'PhpParser\\Internal\\DiffElem' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php',
'PhpParser\\Internal\\Differ' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php',
'PhpParser\\Internal\\PrintableNewAnonClassNode' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php',
@@ -3033,6 +3035,17 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface' => __DIR__ . '/..' . '/symfony/http-foundation/Session/Storage/SessionStorageInterface.php',
'Symfony\\Component\\HttpFoundation\\StreamedJsonResponse' => __DIR__ . '/..' . '/symfony/http-foundation/StreamedJsonResponse.php',
'Symfony\\Component\\HttpFoundation\\StreamedResponse' => __DIR__ . '/..' . '/symfony/http-foundation/StreamedResponse.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\RequestAttributeValueSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseCookieValueSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseFormatSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHasCookie' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHasHeader' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHeaderLocationSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseHeaderLocationSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseHeaderSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsRedirected' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsSuccessful' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseIsUnprocessable' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php',
'Symfony\\Component\\HttpFoundation\\Test\\Constraint\\ResponseStatusCodeSame' => __DIR__ . '/..' . '/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php',
'Symfony\\Component\\HttpFoundation\\UriSigner' => __DIR__ . '/..' . '/symfony/http-foundation/UriSigner.php',
'Symfony\\Component\\HttpFoundation\\UrlHelper' => __DIR__ . '/..' . '/symfony/http-foundation/UrlHelper.php',
'Symfony\\Component\\HttpKernel\\Attribute\\AsController' => __DIR__ . '/..' . '/symfony/http-kernel/Attribute/AsController.php',
@@ -4376,10 +4389,10 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$prefixesPsr0;
$loader->classMap = ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::$prefixesPsr0;
$loader->classMap = ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -6,8 +6,8 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/pear/archive_tar',
$vendorDir . '/pear/pear_exception',
$vendorDir . '/pear/console_getopt',
$vendorDir . '/pear/pear-core-minimal/src',
$vendorDir . '/pear/pear_exception',
$vendorDir . '/pear/archive_tar',
);

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '0f11fd9919aab579586a6f52e1c74f317518040c',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,18 +11,20 @@
),
'versions' => array(
'apereo/phpcas' => array(
'pretty_version' => '1.6.1',
'version' => '1.6.1.0',
'reference' => 'c129708154852656aabb13d8606cd5b12dbbabac',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '57a7744146a963d8fa80192e0ab351051b711ff6',
'type' => 'library',
'install_path' => __DIR__ . '/../apereo/phpcas',
'aliases' => array(),
'aliases' => array(
0 => '1.3.x-dev',
),
'dev_requirement' => false,
),
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '0f11fd9919aab579586a6f52e1c74f317518040c',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -47,9 +49,9 @@
'dev_requirement' => false,
),
'firebase/php-jwt' => array(
'pretty_version' => 'v6.11.1',
'version' => '6.11.1.0',
'reference' => 'd1e91ecf8c598d073d0995afa8cd5c75c6e19e66',
'pretty_version' => 'v7.0.3',
'version' => '7.0.3.0',
'reference' => '28aa0694bcfdfa5e2959c394d5a1ee7a5083629e',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
@@ -83,18 +85,18 @@
'dev_requirement' => false,
),
'league/oauth2-client' => array(
'pretty_version' => '2.8.1',
'version' => '2.8.1.0',
'reference' => '9df2924ca644736c835fc60466a3a60390d334f9',
'pretty_version' => '2.9.0',
'version' => '2.9.0.0',
'reference' => '26e8c5da4f3d78cede7021e09b1330a0fc093d5e',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-client',
'aliases' => array(),
'dev_requirement' => false,
),
'league/oauth2-google' => array(
'pretty_version' => '4.0.1',
'version' => '4.0.1.0',
'reference' => '1b01ba18ba31b29e88771e3e0979e5c91d4afe76',
'pretty_version' => '4.1.0',
'version' => '4.1.0.0',
'reference' => '8b9bb43740ac6d994aca881a35f7bacbe98c0ffb',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-google',
'aliases' => array(),
@@ -103,7 +105,7 @@
'nikic/php-parser' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '8ffc1239ff48ed2476b2672dbcc939fcdc5b0f7a',
'reference' => 'b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(
@@ -130,9 +132,9 @@
'dev_requirement' => false,
),
'pear/pear-core-minimal' => array(
'pretty_version' => 'v1.10.16',
'version' => '1.10.16.0',
'reference' => 'c0f51b45f50683bf5bbf558036854ebc9b54d033',
'pretty_version' => 'v1.10.18',
'version' => '1.10.18.0',
'reference' => 'c7b55789d01de0ce090d289b73f1bbd6a2f113b1',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/pear-core-minimal',
'aliases' => array(),
@@ -279,7 +281,7 @@
'rsky/pear-core-min' => array(
'dev_requirement' => false,
'replaced' => array(
0 => 'v1.10.16',
0 => 'v1.10.18',
),
),
'sabberworm/php-css-parser' => array(
@@ -310,9 +312,9 @@
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '5b088fa41eb9568748dc255c45e4054c387ba73b',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'a0a1690543329685c044362c873b78c6de9d4faa',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
@@ -334,36 +336,36 @@
),
),
'symfony/config' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'd445badf0ad2c2a492e38c0378c39997a56ef97b',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'ce9cb0c0d281aaf188b802d4968e42bfb60701e9',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/config',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '7b1f1c37eff5910ddda2831345467e593a5120ad',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/css-selector' => array(
'pretty_version' => 'v6.4.24',
'version' => '6.4.24.0',
'reference' => '9b784413143701aa3c94ac1869a159a9e53e8761',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'b0314c186f1464de048cce58979ff1625ca88bbb',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/css-selector',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/dependency-injection' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'b17882e933c4c606620247b6708ab53aa3b88753',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '91e49958b8a6092e48e4711894a1aeb1b151c62a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dependency-injection',
'aliases' => array(),
@@ -421,72 +423,72 @@
),
),
'symfony/filesystem' => array(
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '441c6b69f7222aadae7cbf5df588496d5ee37789',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '01ffe0411b842f93c571e5c391f289c3fdd498c3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/filesystem',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/finder' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '24965ca011dac87431729640feef8bcf7b5523e0',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '9590e86be1d1c57bfbb16d0dd040345378c20896',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/form' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => 'b758162fb45024f898640ec27f4ac90be0dbfb8f',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => 'ed9275a133809bb48d949ba6dfdc808a819ebea2',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/form',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/framework-bundle' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '9ef2d0b63b9e855ba351e770a603d89699115801',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5b5d19473f22d699811a41b01cef2462bc42b238',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/framework-bundle',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-foundation' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => 'f1a490cc9d595ba7ebe684220e625d1e472ad278',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5bb346d1b4b2a616e5c3d99b3ee4d5810735c535',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/http-kernel' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '73fa5c999d7f741ca544a97d3c791cc97890ae4d',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '006a49fc4f41ee21a6ca61e69caed1c30b29f07c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-kernel',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mailer' => array(
'pretty_version' => 'v6.4.31',
'version' => '6.4.31.0',
'reference' => '8835f93333474780fda1b987cae37e33c3e026ca',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '01b846f48e53ee4096692a383637a1fa4d577301',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mailer',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/mime' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '7409686879ca36c09fc970a5fa8ff6e93504dba4',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '2b32fbbe10b36a8379efab6e702ad8b917151839',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/mime',
'aliases' => array(),
@@ -583,18 +585,18 @@
'dev_requirement' => false,
),
'symfony/property-info' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => '7d961dbb543fcfaa57fa55e555edd466e90160be',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '916455e4c9dcddbebfd101f29d7983841c3564e0',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/property-info',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/routing' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '0dc6253e864e71b486e8ba4970a56ab849106ebe',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5ab3a3e1a03535ec5ca6ce2d39e4369a1096ae47',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/routing',
'aliases' => array(),
@@ -643,9 +645,9 @@
'dev_requirement' => true,
),
'symfony/string' => array(
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '50590a057841fa6bf69d12eceffce3465b9e32cb',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '2adaf4106f2ef4c67271971bde6d3fe0a6936432',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/string',
'aliases' => array(),
@@ -661,9 +663,9 @@
'dev_requirement' => false,
),
'symfony/twig-bridge' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '1dcf980dd4f79885b986befdeb1c1bc0d6aedfc8',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '5169074f4a88dfb02eeccddaba78edfdf212a9b2',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/twig-bridge',
'aliases' => array(),
@@ -679,9 +681,9 @@
'dev_requirement' => false,
),
'symfony/validator' => array(
'pretty_version' => 'v6.4.33',
'version' => '6.4.33.0',
'reference' => 'da1a40418439c0483ca7e0d4ae4c4f744f6b8536',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '7c3897b7f739d4ab913481e680405ca82d08084d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/validator',
'aliases' => array(),
@@ -706,36 +708,36 @@
'dev_requirement' => false,
),
'symfony/web-profiler-bundle' => array(
'pretty_version' => 'v6.4.32',
'version' => '6.4.32.0',
'reference' => '011f59e3f3d20f60d11b4e78b8dc63504f56e145',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '848bc5d5745500f855bb201d57ae066fd7e67448',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/web-profiler-bundle',
'aliases' => array(),
'dev_requirement' => true,
),
'symfony/yaml' => array(
'pretty_version' => 'v6.4.30',
'version' => '6.4.30.0',
'reference' => '8207ae83da19ee3748d6d4f567b4d9a7c656e331',
'pretty_version' => 'v6.4.34',
'version' => '6.4.34.0',
'reference' => '7bca30dabed7900a08c5ad4f1d6483f881a64d0f',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/yaml',
'aliases' => array(),
'dev_requirement' => false,
),
'tecnickcom/tcpdf' => array(
'pretty_version' => '6.10.0',
'version' => '6.10.0.0',
'reference' => 'ca5b6de294512145db96bcbc94e61696599c391d',
'pretty_version' => '6.11.0',
'version' => '6.11.0.0',
'reference' => '81172e58edb1cfae4019ef150ccbdc0e9a8c85c9',
'type' => 'library',
'install_path' => __DIR__ . '/../tecnickcom/tcpdf',
'aliases' => array(),
'dev_requirement' => false,
),
'thenetworg/oauth2-azure' => array(
'pretty_version' => 'v2.2.2',
'version' => '2.2.2.0',
'reference' => 'be204a5135f016470a9c33e82ab48785bbc11af2',
'pretty_version' => 'v2.2.5',
'version' => '2.2.5.0',
'reference' => '06f1aa023e18cc3ea80df6410c7c2dc5502a3655',
'type' => 'library',
'install_path' => __DIR__ . '/../thenetworg/oauth2-azure',
'aliases' => array(),

View File

@@ -1,5 +1,36 @@
# Changelog
## [7.0.3](https://github.com/firebase/php-jwt/compare/v7.0.2...v7.0.3) (2026-02-18)
### Miscellaneous Chores
* add environment for Release Please job ([#619](https://github.com/firebase/php-jwt/issues/619)) ([300fd02](https://github.com/firebase/php-jwt/commit/300fd02c883f096c9067df652dbd23f62cb5e2a7))
## [7.0.2](https://github.com/firebase/php-jwt/compare/v7.0.1...v7.0.2) (2025-12-16)
### Bug Fixes
* add key length validation for ec keys ([#615](https://github.com/firebase/php-jwt/issues/615)) ([7044f9a](https://github.com/firebase/php-jwt/commit/7044f9ae7e7d175d28cca71714feb236f1c0e252))
## [7.0.0](https://github.com/firebase/php-jwt/compare/v6.11.1...v7.0.0) (2025-12-15)
### ⚠️ ⚠️ ⚠️ Security Fixes ⚠️ ⚠️ ⚠️
* add key size validation ([#613](https://github.com/firebase/php-jwt/issues/613)) ([6b80341](https://github.com/firebase/php-jwt/commit/6b80341bf57838ea2d011487917337901cd71576))
**NOTE**: This fix will cause keys with a size below the minimally allowed size to break.
### Features
* add SensitiveParameter attribute to security-critical parameters ([#603](https://github.com/firebase/php-jwt/issues/603)) ([4dbfac0](https://github.com/firebase/php-jwt/commit/4dbfac0260eeb0e9e643063c99998e3219cc539b))
* store timestamp in `ExpiredException` ([#604](https://github.com/firebase/php-jwt/issues/604)) ([f174826](https://github.com/firebase/php-jwt/commit/f1748260d218a856b6a0c23715ac7fae1d7ca95b))
### Bug Fixes
* validate iat and nbf on payload ([#568](https://github.com/firebase/php-jwt/issues/568)) ([953b2c8](https://github.com/firebase/php-jwt/commit/953b2c88bb445b7e3bb82a5141928f13d7343afd))
## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09)

View File

@@ -186,7 +186,7 @@ $passphrase = '[YOUR_PASSPHRASE]';
// Can be generated with "ssh-keygen -t rsa -m pem"
$privateKeyFile = '/path/to/key-with-passphrase.pem';
// Create a private key of type "resource"
/** @var OpenSSLAsymmetricKey $privateKey */
$privateKey = openssl_pkey_get_private(
file_get_contents($privateKeyFile),
$passphrase

View File

@@ -6,6 +6,8 @@ class ExpiredException extends \UnexpectedValueException implements JWTException
{
private object $payload;
private ?int $timestamp = null;
public function setPayload(object $payload): void
{
$this->payload = $payload;
@@ -15,4 +17,14 @@ class ExpiredException extends \UnexpectedValueException implements JWTException
{
return $this->payload;
}
public function setTimestamp(int $timestamp): void
{
$this->timestamp = $timestamp;
}
public function getTimestamp(): ?int
{
return $this->timestamp;
}
}

View File

@@ -52,7 +52,7 @@ class JWK
*
* @uses parseKey
*/
public static function parseKeySet(array $jwks, ?string $defaultAlg = null): array
public static function parseKeySet(#[\SensitiveParameter] array $jwks, ?string $defaultAlg = null): array
{
$keys = [];
@@ -93,7 +93,7 @@ class JWK
*
* @uses createPemFromModulusAndExponent
*/
public static function parseKey(array $jwk, ?string $defaultAlg = null): ?Key
public static function parseKey(#[\SensitiveParameter] array $jwk, ?string $defaultAlg = null): ?Key
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');

View File

@@ -31,6 +31,8 @@ class JWT
private const ASN1_SEQUENCE = 0x10;
private const ASN1_BIT_STRING = 0x03;
private const RSA_KEY_MIN_LENGTH=2048;
/**
* When checking nbf, iat or expiration times,
* we want to provide some extra leeway time to
@@ -95,7 +97,7 @@ class JWT
*/
public static function decode(
string $jwt,
$keyOrKeyArray,
#[\SensitiveParameter] $keyOrKeyArray,
?stdClass &$headers = null
): stdClass {
// Validate JWT
@@ -127,6 +129,16 @@ class JWT
if (!$payload instanceof stdClass) {
throw new UnexpectedValueException('Payload must be a JSON object');
}
if (isset($payload->iat) && !\is_numeric($payload->iat)) {
throw new UnexpectedValueException('Payload iat must be a number');
}
if (isset($payload->nbf) && !\is_numeric($payload->nbf)) {
throw new UnexpectedValueException('Payload nbf must be a number');
}
if (isset($payload->exp) && !\is_numeric($payload->exp)) {
throw new UnexpectedValueException('Payload exp must be a number');
}
$sig = static::urlsafeB64Decode($cryptob64);
if (empty($header->alg)) {
throw new UnexpectedValueException('Empty algorithm');
@@ -154,7 +166,7 @@ class JWT
// token can actually be used. If it's not yet that time, abort.
if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) {
$ex = new BeforeValidException(
'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) floor($payload->nbf))
'Cannot handle token with nbf prior to ' . \date(DateTime::ATOM, (int) floor($payload->nbf))
);
$ex->setPayload($payload);
throw $ex;
@@ -165,7 +177,7 @@ class JWT
// correctly used the nbf claim).
if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) {
$ex = new BeforeValidException(
'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) floor($payload->iat))
'Cannot handle token with iat prior to ' . \date(DateTime::ATOM, (int) floor($payload->iat))
);
$ex->setPayload($payload);
throw $ex;
@@ -175,6 +187,7 @@ class JWT
if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
$ex = new ExpiredException('Expired token');
$ex->setPayload($payload);
$ex->setTimestamp($timestamp);
throw $ex;
}
@@ -185,11 +198,11 @@ class JWT
* Converts and signs a PHP array into a JWT string.
*
* @param array<mixed> $payload PHP array
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
* @param string $keyId
* @param array<string, string> $head An array with header elements to attach
* @param array<string, string|string[]> $head An array with header elements to attach
*
* @return string A signed JWT
*
@@ -198,7 +211,7 @@ class JWT
*/
public static function encode(
array $payload,
$key,
#[\SensitiveParameter] $key,
string $alg,
?string $keyId = null,
?array $head = null
@@ -226,7 +239,7 @@ class JWT
* Sign a string with a given key and algorithm.
*
* @param string $msg The message to sign
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
*
@@ -236,7 +249,7 @@ class JWT
*/
public static function sign(
string $msg,
$key,
#[\SensitiveParameter] $key,
string $alg
): string {
if (empty(static::$supported_algs[$alg])) {
@@ -248,13 +261,19 @@ class JWT
if (!\is_string($key)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($key, $algorithm);
return \hash_hmac($algorithm, $msg, $key, true);
case 'openssl':
$signature = '';
if (!\is_resource($key) && !openssl_pkey_get_private($key)) {
if (!$key = openssl_pkey_get_private($key)) {
throw new DomainException('OpenSSL unable to validate key');
}
$success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);
}
$success = \openssl_sign($msg, $signature, $key, $algorithm);
if (!$success) {
throw new DomainException('OpenSSL unable to sign data');
}
@@ -293,7 +312,7 @@ class JWT
*
* @param string $msg The original message (header and body)
* @param string $signature The original signature
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string $alg The algorithm
*
* @return bool
@@ -303,7 +322,7 @@ class JWT
private static function verify(
string $msg,
string $signature,
$keyMaterial,
#[\SensitiveParameter] $keyMaterial,
string $alg
): bool {
if (empty(static::$supported_algs[$alg])) {
@@ -313,7 +332,15 @@ class JWT
list($function, $algorithm) = static::$supported_algs[$alg];
switch ($function) {
case 'openssl':
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
if (!$key = openssl_pkey_get_public($keyMaterial)) {
throw new DomainException('OpenSSL unable to validate key');
}
if (str_starts_with($alg, 'RS')) {
self::validateRsaKeyLength($key);
} elseif (str_starts_with($alg, 'ES')) {
self::validateEcKeyLength($key, $alg);
}
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
if ($success === 1) {
return true;
}
@@ -350,6 +377,7 @@ class JWT
if (!\is_string($keyMaterial)) {
throw new InvalidArgumentException('key must be a string when using hmac');
}
self::validateHmacKeyLength($keyMaterial, $algorithm);
$hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
return self::constantTimeEquals($hash, $signature);
}
@@ -457,7 +485,7 @@ class JWT
* @return Key
*/
private static function getKey(
$keyOrKeyArray,
#[\SensitiveParameter] $keyOrKeyArray,
?string $kid
): Key {
if ($keyOrKeyArray instanceof Key) {
@@ -664,4 +692,57 @@ class JWT
return [$pos, $data];
}
/**
* Validate HMAC key length
*
* @param string $key HMAC key material
* @param string $algorithm The algorithm
*
* @throws DomainException Provided key is too short
*/
private static function validateHmacKeyLength(string $key, string $algorithm): void
{
$keyLength = \strlen($key) * 8;
$minKeyLength = (int) \str_replace('SHA', '', $algorithm);
if ($keyLength < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}
/**
* Validate RSA key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @throws DomainException Provided key is too short
*/
private static function validateRsaKeyLength(#[\SensitiveParameter] OpenSSLAsymmetricKey $key): void
{
if (!$keyDetails = openssl_pkey_get_details($key)) {
throw new DomainException('Unable to validate key');
}
if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
throw new DomainException('Provided key is too short');
}
}
/**
* Validate RSA key length
*
* @param OpenSSLAsymmetricKey $key RSA key material
* @param string $algorithm The algorithm
* @throws DomainException Provided key is too short
*/
private static function validateEcKeyLength(
#[\SensitiveParameter] OpenSSLAsymmetricKey $key,
string $algorithm
): void {
if (!$keyDetails = openssl_pkey_get_details($key)) {
throw new DomainException('Unable to validate key');
}
$minKeyLength = (int) \str_replace('ES', '', $algorithm);
if ($keyDetails['bits'] < $minKeyLength) {
throw new DomainException('Provided key is too short');
}
}
}

View File

@@ -10,20 +10,19 @@ use TypeError;
class Key
{
/**
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
* @param string $algorithm
*/
public function __construct(
private $keyMaterial,
#[\SensitiveParameter] private $keyMaterial,
private string $algorithm
) {
if (
!\is_string($keyMaterial)
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
&& !$keyMaterial instanceof OpenSSLCertificate
&& !\is_resource($keyMaterial)
) {
throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
throw new TypeError('Key material must be a string, OpenSSLCertificate, or OpenSSLAsymmetricKey');
}
if (empty($keyMaterial)) {
@@ -46,7 +45,7 @@ class Key
}
/**
* @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
* @return string|OpenSSLAsymmetricKey|OpenSSLCertificate
*/
public function getKeyMaterial()
{

View File

@@ -24,6 +24,7 @@ This package is compliant with [PSR-1][], [PSR-2][], [PSR-4][], and [PSR-7][]. I
We support the following versions of PHP:
* PHP 8.5
* PHP 8.4
* PHP 8.3
* PHP 8.2

View File

@@ -6,7 +6,7 @@
"sort-packages": true
},
"require": {
"php": "^7.1 || >=8.0.0 <8.5.0",
"php": "^7.1 || >=8.0.0 <8.6.0",
"ext-json": "*",
"guzzlehttp/guzzle": "^6.5.8 || ^7.4.5"
},

View File

@@ -1,5 +1,12 @@
OAuth 2.0 Google Provider Changelog
## 4.1.0 - 2025-12-15
### Added
- Added getEmailVerified(), isEmailTrustworthy() to user definition, #132 by @dt-thomas-durand
## 4.0.1 - 2022-03-17
### Changed

View File

@@ -1,6 +1,6 @@
# Google Provider for OAuth 2.0 Client
[![Build Status](https://img.shields.io/github/workflow/status/thephpleague/oauth2-google/test/main)](https://github.com/thephpleague/oauth2-google/actions/workflows/test.yaml)
[![Build Status](https://img.shields.io/github/actions/workflow/status/thephpleague/oauth2-google/ci.yml?branch=main)](https://github.com/thephpleague/oauth2-google/actions/workflows/ci.yml)
[![Code Coverage](https://img.shields.io/codecov/c/gh/thephpleague/oauth2-google)](https://app.codecov.io/gh/thephpleague/oauth2-google)
[![License](https://img.shields.io/packagist/l/league/oauth2-google)](https://github.com/thephpleague/oauth2-google/blob/main/LICENSE)
[![Latest Stable Version](https://img.shields.io/packagist/v/league/oauth2-google)](https://packagist.org/packages/league/oauth2-google)
@@ -22,6 +22,8 @@ The following versions of PHP are supported.
* PHP 7.4
* PHP 8.0
* PHP 8.1
* PHP 8.2
* PHP 8.3
This package uses [OpenID Connect][openid-connect] to authenticate users with
Google accounts.

View File

@@ -72,6 +72,36 @@ class GoogleUser implements ResourceOwnerInterface
return $this->getResponseValue('email');
}
/**
* Get email_verified attribute.
*
* @return bool|null
*/
public function getEmailVerified(): ?bool
{
return $this->getResponseValue('email_verified');
}
/**
* Returns whether the email is trustable enough to be used for authentication purpose.
*
* @see https://developers.google.com/identity/gsi/web/guides/verify-google-id-token
*/
public function isEmailTrustworthy(): bool
{
$email = $this->getEmail();
if (! $email) {
return false;
}
if ('@gmail.com' === substr($email, -10)) {
return true;
}
if ($this->getHostedDomain() && $this->getEmailVerified()) {
return true;
}
return false;
}
/**
* Get hosted domain.
*

View File

@@ -3,10 +3,7 @@
namespace PhpParser;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use Exception;
use function array_merge;
@@ -20,8 +17,6 @@ use function array_merge;
* following node types:
*
* * All Scalar\MagicConst\* nodes.
* * Expr\ConstFetch nodes. Only null/false/true are already handled by this class.
* * Expr\ClassConstFetch nodes.
*
* The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate.
*
@@ -31,13 +26,7 @@ use function array_merge;
*/
class ConstExprEvaluator {
/** @var callable|null */
private $fallbackEvaluator;
/** @var array $functionsWhiteList */
private $functionsWhiteList;
/** @var array $staticCallsWhitelist */
private $staticCallsWhitelist;
protected $fallbackEvaluator;
/**
* Create a constant expression evaluator.
@@ -53,17 +42,6 @@ class ConstExprEvaluator {
"Expression of type {$expr->getType()} cannot be evaluated"
);
};
$this->functionsWhiteList = [];
$this->staticCallsWhitelist = [];
}
public function setFunctionsWhitelist(array $functionsWhiteList): void {
$this->functionsWhiteList = $functionsWhiteList;
}
public function setStaticCallsWhitelist(array $staticCallsWhitelist): void {
$this->staticCallsWhitelist = $staticCallsWhitelist;
}
/**
@@ -123,7 +101,7 @@ class ConstExprEvaluator {
}
/** @return mixed */
private function evaluate(Expr $expr) {
protected function evaluate(Expr $expr) {
if ($expr instanceof Scalar\Int_
|| $expr instanceof Scalar\Float_
|| $expr instanceof Scalar\String_
@@ -135,10 +113,6 @@ class ConstExprEvaluator {
return $this->evaluateArray($expr);
}
if ($expr instanceof Expr\Variable) {
return $this->evaluateVariable($expr);
}
// Unary operators
if ($expr instanceof Expr\UnaryPlus) {
return +$this->evaluate($expr->expr);
@@ -169,37 +143,13 @@ class ConstExprEvaluator {
return $this->evaluateConstFetch($expr);
}
if ($expr instanceof Expr\Isset_) {
return $this->evaluateIsset($expr);
}
if ($expr instanceof Expr\ClassConstFetch) {
return $this->evaluateClassConstFetch($expr);
}
if ($expr instanceof Expr\ClassConstFetch) {
return $this->evaluateClassConstFetch($expr);
}
if ($expr instanceof Expr\Cast) {
return $this->evaluateCast($expr);
}
if ($expr instanceof Expr\StaticPropertyFetch) {
return $this->evaluateStaticPropertyFetch($expr);
}
if ($expr instanceof Expr\FuncCall) {
return $this->evaluateFuncCall($expr);
}
if ($expr instanceof Expr\StaticCall) {
return $this->evaluateStaticCall($expr);
}
if ($expr instanceof Expr\NullsafePropertyFetch||$expr instanceof Expr\PropertyFetch) {
return $this->evaluatePropertyFetch($expr);
}
if ($expr instanceof Expr\NullsafeMethodCall||$expr instanceof Expr\MethodCall) {
return $this->evaluateMethodCall($expr);
}
if ($expr instanceof Expr\Cast) {
return $this->evaluateCast($expr);
}
return ($this->fallbackEvaluator)($expr);
}
@@ -231,15 +181,12 @@ class ConstExprEvaluator {
/** @return mixed */
private function evaluateBinaryOp(Expr\BinaryOp $expr) {
if ($expr instanceof Expr\BinaryOp\Coalesce) {
try {
$var = $this->evaluate($expr->left);
} catch(\Throwable $t) {
//left expression cannot be evaluated (! isset for exeample)
return $this->evaluate($expr->right);
}
return $var ?? $this->evaluate($expr->right);
if ($expr instanceof Expr\BinaryOp\Coalesce
&& $expr->left instanceof Expr\ArrayDimFetch
) {
// This needs to be special cased to respect BP_VAR_IS fetch semantics
return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
?? $this->evaluate($expr->right);
}
// The evaluate() calls are repeated in each branch, because some of the operators are
@@ -284,272 +231,79 @@ class ConstExprEvaluator {
/** @return mixed */
private function evaluateConstFetch(Expr\ConstFetch $expr) {
try {
$name = $expr->name;
if(! is_string($name)) {
//PHP_VERSION_ID usecase
$name = $name->name;
}
try {
$name = $expr->name->name;
if (defined($name)) {
return constant($name);
}
} catch(\Throwable $t) {}
if (defined($name)) {
return constant($name);
}
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/** @return bool */
private function evaluateIsset(Expr\Isset_ $expr) {
try {
foreach ($expr->vars as $var) {
$var = $this->evaluate($var);
if (! isset($var)) {
return false;
}
}
/** @return mixed */
private function evaluateClassConstFetch(Expr\ClassConstFetch $expr) {
try {
$classname = $expr->class->name;
$property = $expr->name->name;
return true;
} catch(\Throwable $t) {
return false;
}
}
if ('class' === $property) {
return $classname;
}
/** @return mixed */
private function evaluateClassConstFetch(Expr\ClassConstFetch $expr) {
try {
$classname = $expr->class->name;
$property = $expr->name->name;
if (class_exists($classname)) {
$class = new \ReflectionClass($classname);
if (array_key_exists($property, $class->getConstants())) {
$oReflectionConstant = $class->getReflectionConstant($property);
if ($oReflectionConstant->isPublic()) {
return $class->getConstant($property);
}
}
}
} catch (\Throwable $t) {
}
if ('class' === $property) {
return $classname;
}
return ($this->fallbackEvaluator)($expr);
}
if (class_exists($classname)) {
$class = new \ReflectionClass($classname);
if (array_key_exists($property, $class->getConstants())) {
$oReflectionConstant = $class->getReflectionConstant($property);
if ($oReflectionConstant->isPublic()) {
return $class->getConstant($property);
}
}
}
} catch(\Throwable $t) {}
/** @return mixed */
private function evaluateCast(Expr\Cast $expr) {
try {
$subexpr = $this->evaluate($expr->expr);
$type = get_class($expr);
switch ($type) {
case Expr\Cast\Array_::class:
return (array) $subexpr;
return ($this->fallbackEvaluator)($expr);
}
case Expr\Cast\Bool_::class:
return (bool) $subexpr;
/** @return mixed */
private function evaluateCast(Expr\Cast $expr) {
try {
$subexpr = $this->evaluate($expr->expr);
$type = get_class($expr);
switch ($type) {
case Expr\Cast\Array_::class:
return (array) $subexpr;
case Expr\Cast\Double::class:
switch ($expr->getAttribute("kind")) {
case Expr\Cast\Double::KIND_DOUBLE:
return (float) $subexpr;
case Expr\Cast\Bool_::class:
return (bool) $subexpr;
case Expr\Cast\Double::KIND_FLOAT:
case Expr\Cast\Double::KIND_REAL:
return (float) $subexpr;
}
case Expr\Cast\Double::class:
switch ($expr->getAttribute("kind")) {
case Expr\Cast\Double::KIND_DOUBLE:
return (double) $subexpr;
break;
case Expr\Cast\Double::KIND_FLOAT:
case Expr\Cast\Double::KIND_REAL:
return (float) $subexpr;
}
case Expr\Cast\Int_::class:
return (int) $subexpr;
break;
case Expr\Cast\Object_::class:
return (object) $subexpr;
case Expr\Cast\Int_::class:
return (int) $subexpr;
case Expr\Cast\String_::class:
return (string) $subexpr;
}
} catch (\Throwable $t) {
}
case Expr\Cast\Object_::class:
return (object) $subexpr;
case Expr\Cast\String_::class:
return (string) $subexpr;
}
} catch(\Throwable $t) {}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateStaticPropertyFetch(Expr\StaticPropertyFetch $expr) {
try {
$classname = $expr->class->name;
if ($expr->name instanceof Identifier) {
$property = $expr->name->name;
} else {
$property = $this->evaluate($expr->name);
}
if (class_exists($classname)) {
$class = new \ReflectionClass($classname);
if (array_key_exists($property, $class->getStaticProperties())) {
$oReflectionProperty = $class->getProperty($property);
if ($oReflectionProperty->isPublic()) {
return $class->getStaticPropertyValue($property);
}
}
}
}
catch (\Throwable $t) {}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateFuncCall(Expr\FuncCall $expr) {
try {
$name = $expr->name;
if ($name instanceof Name) {
$function = $name->name;
} else {
$function = $this->evaluate($name);
}
if (! in_array($function, $this->functionsWhiteList)) {
throw new Exception("FuncCall $function not supported");
}
$args=[];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[]=$arg->value->value;
}
$reflection_function = new \ReflectionFunction($function);
return $reflection_function->invoke(...$args);
}
catch (\Throwable $t) {}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateVariable(Expr\Variable $expr) {
try {
$name = $expr->name;
if (array_key_exists($name, get_defined_vars())) {
return $$name;
}
if (array_key_exists($name, $GLOBALS)) {
global $$name;
return $$name;
}
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateStaticCall(Expr\StaticCall $expr) {
try {
$class = $expr->class->name;
if ($expr->name instanceof Identifier) {
$method = $expr->name->name;
} else {
$method = $this->evaluate($expr->name);
}
$static_call_description = "$class::$method";
if (! in_array($static_call_description, $this->staticCallsWhitelist)) {
throw new Exception("StaticCall $static_call_description not supported");
}
$args=[];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[]=$arg->value->value;
}
$class = new \ReflectionClass($class);
$method = $class->getMethod($method);
if ($method->isPublic()) {
return $method->invokeArgs(null, $args);
}
} catch (\Throwable $t) {}
return ($this->fallbackEvaluator)($expr);
}
/**
* @param \PhpParser\Node\Expr\NullsafePropertyFetch|\PhpParser\Node\Expr\PropertyFetch $expr
*
* @return mixed
*/
private function evaluatePropertyFetch($expr) {
try {
$var = $this->evaluate($expr->var);
} catch (\Throwable $t) {
$var = null;
}
if (! is_null($var)) {
try {
if ($expr->name instanceof Identifier) {
$name = $expr->name->name;
} else {
$name = $this->evaluate($expr->name);
}
$reflectionClass = new \ReflectionClass(get_class($var));
$property = $reflectionClass->getProperty($name);
if ($property->isPublic()) {
return $property->getValue($var);
}
}
catch (\Throwable $t) {}
} else if ($expr instanceof Expr\NullsafePropertyFetch) {
return null;
}
return ($this->fallbackEvaluator)($expr);
}
/**
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\NullsafeMethodCall $expr
*
* @return mixed
*/
private function evaluateMethodCall($expr) {
try {
$var = $this->evaluate($expr->var);
} catch (\Throwable $t) {
$var = null;
}
if (! is_null($var)) {
try {
$args = [];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[] = $arg->value->value;
}
if ($expr->name instanceof Identifier) {
$name = $expr->name->name;
} else {
$name = $this->evaluate($expr->name);
}
$reflectionClass = new \ReflectionClass(get_class($var));
$method = $reflectionClass->getMethod($name);
if ($method->isPublic()) {
return $method->invokeArgs($var, $args);
}
}
catch (\Throwable $t) {}
} else if ($expr instanceof Expr\NullsafeMethodCall) {
return null;
}
return ($this->fallbackEvaluator)($expr);
}
return ($this->fallbackEvaluator)($expr);
}
}

View File

@@ -0,0 +1,6 @@
<?php declare(strict_types=1);
namespace PhpParser;
class ExprEvaluationException extends \Exception {
}

View File

@@ -0,0 +1,363 @@
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use Exception;
use function array_merge;
/**
* Evaluates any expressions.
*
* To handle not-supported expressions you need, please provide your own fallback evaluator
*
* The fallback evaluator should throw ExprEvaluationException for nodes it cannot evaluate.
*
* Method/function evaluation relies on white lists. Please specify which ones are allowed to be evaluated/called before evaluation
* (@see setStaticCallsWhitelist/ @see setFunctionsWhitelist.
*/
class ExprEvaluator extends ConstExprEvaluator {
/** @var callable|null */
protected $fallbackEvaluator;
/** @var array<string> */
private array $functionsWhiteList = [];
/** @var array<string> */
private array $staticCallsWhitelist = [];
/**
* Create a constant expression evaluator.
*
* The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
* class doc comment for more information.
*
* @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
*/
public function __construct(?callable $fallbackEvaluator = null) {
parent::__construct($fallbackEvaluator);
$this->fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) {
throw new ExprEvaluationException(
"Expression of type {$expr->getType()} cannot be evaluated"
);
};
}
/**
* @param array<string> $functionsWhiteList
*/
public function setFunctionsWhitelist(array $functionsWhiteList): void {
$this->functionsWhiteList = $functionsWhiteList;
}
/**
* @param array<string> $staticCallsWhitelist
*/
public function setStaticCallsWhitelist(array $staticCallsWhitelist): void {
$this->staticCallsWhitelist = $staticCallsWhitelist;
}
/**
* Silently evaluates a constant expression into a PHP value.
*
* Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.
* The original source of the exception is available through getPrevious().
*
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
* constructor will be invoked. By default, if no fallback is provided, an exception of type
* ConstExprEvaluationException is thrown.
*
* See class doc comment for caveats and limitations.
*
* @param Expr $expr Constant expression to evaluate
*
* @return mixed Result of evaluation
*
* @throws ExprEvaluationException if the expression cannot be evaluated or an error occurred
*/
public function evaluateSilently(Expr $expr) {
set_error_handler(function ($num, $str, $file, $line) {
throw new \ErrorException($str, 0, $num, $file, $line);
});
try {
return $this->evaluate($expr);
} catch (\Throwable $e) {
if (!$e instanceof ExprEvaluationException) {
$e = new ExprEvaluationException(
"An error occurred during expression evaluation", 0, $e);
}
throw $e;
} finally {
restore_error_handler();
}
}
/**
* Directly evaluates a constant expression into a PHP value.
*
* May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these
* into a ConstExprEvaluationException.
*
* If some part of the expression cannot be evaluated, the fallback evaluator passed to the
* constructor will be invoked. By default, if no fallback is provided, an exception of type
* ConstExprEvaluationException is thrown.
*
* See class doc comment for caveats and limitations.
*
* @param Expr $expr Constant expression to evaluate
*
* @return mixed Result of evaluation
*
* @throws ExprEvaluationException if the expression cannot be evaluated
*/
public function evaluateDirectly(Expr $expr) {
return $this->evaluate($expr);
}
/** @return mixed */
protected function evaluate(Expr $expr) {
try {
return parent::evaluate($expr);
} catch (\Throwable $t) {
}
if ($expr instanceof Expr\Variable) {
return $this->evaluateVariable($expr);
}
if ($expr instanceof Expr\BinaryOp\Coalesce) {
try {
$var = $this->evaluate($expr->left);
} catch (\Throwable $t) {
//left expression cannot be evaluated (! isset for exeample)
return $this->evaluate($expr->right);
}
return $var ?? $this->evaluate($expr->right);
}
if ($expr instanceof Expr\Isset_) {
return $this->evaluateIsset($expr);
}
if ($expr instanceof Expr\StaticPropertyFetch) {
return $this->evaluateStaticPropertyFetch($expr);
}
if ($expr instanceof Expr\FuncCall) {
return $this->evaluateFuncCall($expr);
}
if ($expr instanceof Expr\StaticCall) {
return $this->evaluateStaticCall($expr);
}
if ($expr instanceof Expr\NullsafePropertyFetch || $expr instanceof Expr\PropertyFetch) {
return $this->evaluatePropertyFetch($expr);
}
if ($expr instanceof Expr\NullsafeMethodCall || $expr instanceof Expr\MethodCall) {
return $this->evaluateMethodCall($expr);
}
return ($this->fallbackEvaluator)($expr);
}
/** @return bool */
private function evaluateIsset(Expr\Isset_ $expr) {
try {
foreach ($expr->vars as $var) {
$var = $this->evaluate($var);
if (! isset($var)) {
return false;
}
}
return true;
} catch (\Throwable $t) {
return false;
}
}
/** @return mixed */
private function evaluateStaticPropertyFetch(Expr\StaticPropertyFetch $expr) {
try {
$classname = $expr->class->name;
if ($expr->name instanceof Identifier) {
$property = $expr->name->name;
} else {
$property = $this->evaluate($expr->name);
}
if (class_exists($classname)) {
$class = new \ReflectionClass($classname);
if (array_key_exists($property, $class->getStaticProperties())) {
$oReflectionProperty = $class->getProperty($property);
if ($oReflectionProperty->isPublic()) {
return $class->getStaticPropertyValue($property);
}
}
}
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateFuncCall(Expr\FuncCall $expr) {
try {
$name = $expr->name;
if ($name instanceof Name) {
$function = $name->name;
} else {
$function = $this->evaluate($name);
}
if (! in_array($function, $this->functionsWhiteList)) {
throw new Exception("FuncCall $function not supported");
}
$args = [];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[] = $this->evaluate($arg->value);
}
$reflection_function = new \ReflectionFunction($function);
return $reflection_function->invoke(...$args);
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateVariable(Expr\Variable $expr) {
try {
$name = $expr->name;
if (array_key_exists($name, get_defined_vars())) {
return $$name;
}
if (array_key_exists($name, $GLOBALS)) {
global $$name;
return $$name;
}
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/** @return mixed */
private function evaluateStaticCall(Expr\StaticCall $expr) {
try {
$class = $expr->class->name;
if ($expr->name instanceof Identifier) {
$method = $expr->name->name;
} else {
$method = $this->evaluate($expr->name);
}
$static_call_description = "$class::$method";
if (! in_array($static_call_description, $this->staticCallsWhitelist)) {
throw new Exception("StaticCall $static_call_description not supported");
}
$args = [];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[] = $this->evaluate($arg->value);
}
$class = new \ReflectionClass($class);
$method = $class->getMethod($method);
if ($method->isPublic()) {
return $method->invokeArgs(null, $args);
}
} catch (\Throwable $t) {
}
return ($this->fallbackEvaluator)($expr);
}
/**
* @param \PhpParser\Node\Expr\NullsafePropertyFetch|\PhpParser\Node\Expr\PropertyFetch $expr
*
* @return mixed
*/
private function evaluatePropertyFetch($expr) {
try {
$var = $this->evaluate($expr->var);
} catch (\Throwable $t) {
$var = null;
}
if (! is_null($var)) {
try {
if ($expr->name instanceof Identifier) {
$name = $expr->name->name;
} else {
$name = $this->evaluate($expr->name);
}
$reflectionClass = new \ReflectionClass(get_class($var));
$property = $reflectionClass->getProperty($name);
if ($property->isPublic()) {
return $property->getValue($var);
}
} catch (\Throwable $t) {
}
} elseif ($expr instanceof Expr\NullsafePropertyFetch) {
return null;
}
return ($this->fallbackEvaluator)($expr);
}
/**
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\NullsafeMethodCall $expr
*
* @return mixed
*/
private function evaluateMethodCall($expr) {
try {
$var = $this->evaluate($expr->var);
} catch (\Throwable $t) {
$var = null;
}
if (! is_null($var)) {
try {
$args = [];
foreach ($expr->args as $arg) {
/** @var \PhpParser\Node\Arg $arg */
$args[] = $this->evaluate($arg->value);
}
if ($expr->name instanceof Identifier) {
$name = $expr->name->name;
} else {
$name = $this->evaluate($expr->name);
}
$reflectionClass = new \ReflectionClass(get_class($var));
$method = $reflectionClass->getMethod($name);
if ($method->isPublic()) {
return $method->invokeArgs($var, $args);
}
} catch (\Throwable $t) {
}
} elseif ($expr instanceof Expr\NullsafeMethodCall) {
return null;
}
return ($this->fallbackEvaluator)($expr);
}
}

View File

@@ -216,9 +216,13 @@ class PEAR
public function __call($method, $arguments)
{
if (!isset(self::$bivalentMethods[$method])) {
trigger_error(
'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
);
if (PHP_VERSION_ID < 70000) {
trigger_error(
'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
);
} else {
throw new Error('Call to undefined method PEAR::' . $method . '()');
}
}
return call_user_func_array(
array(__CLASS__, '_' . $method),
@@ -229,9 +233,13 @@ class PEAR
public static function __callStatic($method, $arguments)
{
if (!isset(self::$bivalentMethods[$method])) {
trigger_error(
'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
);
if (PHP_VERSION_ID < 70000) {
trigger_error(
'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
);
} else {
throw new Error('Call to undefined method PEAR::' . $method . '()');
}
}
return call_user_func_array(
array(__CLASS__, '_' . $method),

View File

@@ -32,6 +32,8 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
{
private const MAX_KEY_LENGTH = 255;
private static int $savepointCounter = 0;
private MarshallerInterface $marshaller;
private Connection $conn;
private string $platformName;
@@ -244,6 +246,26 @@ class DoctrineDbalAdapter extends AbstractAdapter implements PruneableInterface
return $failed;
}
if ($this->conn->isTransactionActive() && $this->conn->getDatabasePlatform()->supportsSavepoints()) {
$savepoint = 'cache_save_'.++self::$savepointCounter;
try {
$this->conn->createSavepoint($savepoint);
$failed = $this->doSaveInner($values, $lifetime, $failed);
$this->conn->releaseSavepoint($savepoint);
return $failed;
} catch (\Throwable $e) {
$this->conn->rollbackSavepoint($savepoint);
throw $e;
}
}
return $this->doSaveInner($values, $lifetime, $failed);
}
private function doSaveInner(array $values, int $lifetime, array $failed): array|bool
{
$platformName = $this->getPlatformName();
$insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?)";

View File

@@ -108,7 +108,7 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface
// - trailing space removal
// - case-insensitivity
// - language processing like é == e
'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL), ENGINE = InnoDB",
'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL) ENGINE = InnoDB",
'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)",
'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)",
'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(255) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)",

View File

@@ -175,9 +175,26 @@ trait RedisTrait
}
$params += $query + $options + self::$defaultConnectionOptions;
$params['auth'] ??= $auth;
if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) {
$booleanStreamOptions = [
'allow_self_signed',
'capture_peer_cert',
'capture_peer_cert_chain',
'disable_compression',
'SNI_enabled',
'verify_peer',
'verify_peer_name',
];
foreach ($params['ssl'] ?? [] as $streamOption => $value) {
if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) {
$params['ssl'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL);
}
}
if (!isset($params['redis_sentinel'])) {
$params['auth'] ??= $auth;
} elseif (!class_exists(\Predis\Client::class) && !class_exists(\RedisSentinel::class) && !class_exists(Sentinel::class)) {
throw new CacheException('Redis Sentinel support requires one of: "predis/predis", "ext-redis >= 5.2", "ext-relay".');
}
@@ -246,6 +263,10 @@ trait RedisTrait
$options['auth'] = $params['auth'];
}
if (null !== $params['ssl'] && version_compare(phpversion('redis'), '6.2.0', '>=')) {
$options['ssl'] = $params['ssl'];
}
$sentinel = new \RedisSentinel($options);
} else {
$extra = $passAuth ? [$params['auth']] : [];
@@ -268,21 +289,6 @@ trait RedisTrait
$extra = [
'stream' => $params['ssl'] ?? null,
];
$booleanStreamOptions = [
'allow_self_signed',
'capture_peer_cert',
'capture_peer_cert_chain',
'disable_compression',
'SNI_enabled',
'verify_peer',
'verify_peer_name',
];
foreach ($extra['stream'] ?? [] as $streamOption => $value) {
if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) {
$extra['stream'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL);
}
}
if (null !== $params['auth']) {
$extra['auth'] = $params['auth'];
@@ -388,12 +394,12 @@ trait RedisTrait
if ($params['dbindex']) {
$params['parameters']['database'] = $params['dbindex'];
}
if (\is_array($params['auth'])) {
if (\is_array($auth)) {
// ACL
$params['parameters']['username'] = $params['auth'][0];
$params['parameters']['password'] = $params['auth'][1];
} elseif (null !== $params['auth']) {
$params['parameters']['password'] = $params['auth'];
$params['parameters']['username'] = $auth[0];
$params['parameters']['password'] = $auth[1];
} elseif (null !== $auth) {
$params['parameters']['password'] = $auth;
}
if (isset($params['ssl'])) {

View File

@@ -72,27 +72,40 @@ abstract class FileLoader extends Loader
*/
public function import(mixed $resource, ?string $type = null, bool $ignoreErrors = false, ?string $sourceResource = null, string|array|null $exclude = null)
{
if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) {
$excluded = [];
foreach ((array) $exclude as $pattern) {
foreach ($this->glob($pattern, true, $_, false, true) as $path => $info) {
// normalize Windows slashes and remove trailing slashes
$excluded[rtrim(str_replace('\\', '/', $path), '/')] = true;
}
$excluded = [];
foreach ((array) $exclude as $pattern) {
foreach ($this->glob($pattern, true, $_, false, true) as $path => $info) {
// normalize Windows slashes and remove trailing slashes
$excluded[rtrim(str_replace('\\', '/', $path), '/')] = true;
}
}
if (\is_string($resource) && !class_exists($resource)) {
$isGlobPattern = \strlen($resource) !== strcspn($resource, '*?{[');
if (!$isGlobPattern && $excluded) {
$resource = rtrim(str_replace('\\', '/', $resource), '/');
$resource .= '/**/*';
$isGlobPattern = true;
}
$ret = [];
$isSubpath = 0 !== $i && str_contains(substr($resource, 0, $i), '/');
foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath, false, $excluded) as $path => $info) {
if (null !== $res = $this->doImport($path, 'glob' === $type ? null : $type, $ignoreErrors, $sourceResource)) {
$ret[] = $res;
if ($isGlobPattern && !str_contains($resource, "\n")) {
$ret = [];
$i = strcspn($resource, '*?{[');
$isSubpath = 0 !== $i && str_contains(substr($resource, 0, $i), '/');
foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath, false, $excluded) as $path => $info) {
if (null !== $res = $this->doImport($path, 'glob' === $type ? null : $type, $ignoreErrors, $sourceResource)) {
$ret[] = $res;
}
$isSubpath = true;
}
$isSubpath = true;
}
if ($isSubpath) {
return isset($ret[1]) ? $ret : ($ret[0] ?? null);
if ($isSubpath) {
return isset($ret[1]) ? $ret : ($ret[0] ?? null);
}
}
} elseif (\is_array($resource) && $excluded) {
$resource['_excluded'] = $excluded;
}
return $this->doImport($resource, $type, $ignoreErrors, $sourceResource);

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\Config\Resource;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
@@ -212,5 +213,12 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
yield ServiceSubscriberInterface::class;
yield print_r($class->name::getSubscribedServices(), true);
}
if (interface_exists(FormTypeExtensionInterface::class, false) && $class->isSubclassOf(FormTypeExtensionInterface::class)) {
yield FormTypeExtensionInterface::class;
foreach ($class->name::getExtendedTypes() as $key => $value) {
yield $key.print_r($value, true);
}
}
}
}

View File

@@ -761,6 +761,21 @@ class Application implements ResetInterface
}));
}
// check whether all commands left are aliases to the same one
if (\count($commands) > 1) {
$uniqueCommands = array_unique(array_map(function ($nameOrAlias) use (&$commandList) {
if (!$commandList[$nameOrAlias] instanceof Command) {
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
}
return $commandList[$nameOrAlias]->getName();
}, $commands));
if (1 === \count($uniqueCommands)) {
$commands = [reset($uniqueCommands)];
}
}
if (\count($commands) > 1) {
$usableWidth = $this->terminal->getWidth() - 10;
$abbrevs = array_values($commands);

View File

@@ -115,24 +115,30 @@ final class CompleteCommand extends Command
'<info>Messages:</>',
]);
$command = $this->findCommand($completionInput, $output);
if ($command = $this->findCommand($completionInput, $output)) {
$command->mergeApplicationDefinition();
$completionInput->bind($command->getDefinition());
}
if (null === $command) {
$this->log(' No command found, completing using the Application class.');
$this->getApplication()->complete($completionInput, $suggestions);
} elseif (
$completionInput->mustSuggestArgumentValuesFor('command')
&& $command->getName() !== $completionInput->getCompletionValue()
&& !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)
) {
$this->log(' No command found, completing using the Application class.');
$this->log(' Command found, completing command name.');
// expand shortcut names ("cache:cl<TAB>") into their full name ("cache:clear")
$suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));
$commandNames = array_filter(array_merge([$command->getName()], $command->getAliases()));
foreach ($commandNames as $name) {
if (str_starts_with($name, $completionInput->getCompletionValue())) {
$commandNames = [$name];
break;
}
}
$suggestions->suggestValues($commandNames);
} else {
$command->mergeApplicationDefinition();
$completionInput->bind($command->getDefinition());
if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
$this->log(' Completing option names for the <comment>'.($command instanceof LazyCommand ? $command->getCommand() : $command)::class.'</> command.');

View File

@@ -22,7 +22,7 @@ final class RunCommandFailedException extends RuntimeException
{
parent::__construct(
$exception instanceof \Throwable ? $exception->getMessage() : $exception,
$exception instanceof \Throwable ? $exception->getCode() : 0,
$exception instanceof \Throwable && \is_int($exception->getCode()) ? $exception->getCode() : 0,
$exception instanceof \Throwable ? $exception : null,
);
}

View File

@@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
/**
@@ -140,7 +141,9 @@ class ProgressIndicator
$this->message = $message;
$this->display();
$this->output->writeln('');
if (!$this->output instanceof ConsoleSectionOutput) {
$this->output->writeln('');
}
$this->started = false;
}
@@ -207,7 +210,9 @@ class ProgressIndicator
*/
private function overwrite(string $message): void
{
if ($this->output->isDecorated()) {
if ($this->output instanceof ConsoleSectionOutput) {
$this->output->overwrite($message);
} elseif ($this->output->isDecorated()) {
$this->output->write("\x0D\x1B[2K");
$this->output->write($message);
} else {

View File

@@ -474,6 +474,8 @@ class QuestionHelper extends Helper
try {
return $question->getValidator()($interviewer());
} catch (MissingInputException $e) {
throw $error ?? $e;
} catch (RuntimeException $e) {
throw $e;
} catch (\Exception $error) {

View File

@@ -104,7 +104,7 @@ class SymfonyStyle extends OutputStyle
public function listing(array $elements)
{
$this->autoPrependText();
$elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements);
$elements = array_map(static fn ($element) => \sprintf(' * %s', $element), $elements);
$this->writeln($elements);
$this->newLine();
@@ -475,12 +475,14 @@ class SymfonyStyle extends OutputStyle
$message = OutputFormatter::escape($message);
}
$message = str_replace("\r\n", "\n", $message);
$lines = array_merge(
$lines,
explode(\PHP_EOL, $outputWrapper->wrap(
explode("\n", $outputWrapper->wrap(
$message,
$this->lineLength - $prefixLength - $indentLength,
\PHP_EOL
"\n"
))
);

Some files were not shown because too many files have changed in this diff Show More